Repository navigation
feat(tui): follow the viewport with the pinned prompt header and jump on click - #6830
Merged
Hmbown merged 9 commits intoOct 3, 2026
Merged
Conversation
fix(compaction): survive a provider request-body 413 while making room
docs(i18n): complete the Tier-2 should-have docs for EPIC codewhale-hq#5482
The pinned user-prompt header used to track only the newest user message: once that message left the viewport the header vanished, and it only came back after the viewport cleared the whole turn. Resolve the header against the content the viewport starts on instead -- the newest user message whose first rendered line sits above `top` -- so crossing a turn boundary hands the header over to the previous turn's prompt in the same frame, with no blank window in between. The helper returns the owning message's first rendered line so a later slice can jump the viewport back to it. Signed-off-by: Shizuku <2163018547@qq.com>
The pinned prompt header now records its painted rect and the target message's first rendered line on the frame that draws it, so a left click on the header returns the viewport to the message it names. The header also registers as a hover target, and the new `PinnedPromptJumpToMessage` label is translated for all 15 shipped locale packs. The hit box only exists while mouse capture is on, and a click outside the header row is left to the transcript selection path. Signed-off-by: Shizuku <2163018547@qq.com>
Review follow-up (SpikeBot 003): a user message opening on a blank line was picked as the pin target and then failed the first-line render check, returning None instead of handing over to an older message -- a drop-out on the very path this feature keeps covered. Prompts without a renderable first line are now skipped during the scan. Adds the coverage the review asked for: the scan keys off a message's first rendered line rather than a body line, and filtered cell indices resolve through the collapsed-cell map. Signed-off-by: Shizuku <2163018547@qq.com>
Review follow-up (SpikeBot 005, posted on this PR): - The agent-focus sampling path builds the main ChatWidget only for its ocean column, but that constructor recorded the pinned header's hit box while the focus pane paints no such header — the focus banner row became an invisible hot zone that answered clicks and hover. The focus branch now drops the stale box. - Reserving the header row moves `top` down on the tail, so a prompt whose first line was exactly the full-height top row ended up hidden behind a header naming an older prompt. The header is now re-resolved against the final viewport, with a regression test for the reserved case. - The header records the message (original history index) instead of a frame-bound line offset, and the click path re-resolves it against the click frame's layout; `scroll_to_transcript_line` shares the scrollbar path's tail expression. - Adds the render -> click -> land end-to-end case the review asked for. Signed-off-by: Shizuku <2163018547@qq.com>
Hmbown
pushed a commit
that referenced
this pull request
Oct 3, 2026
Retain the real main parent 296c05d and the original PR merge/commit ancestry for #6819 (@Guan0923), #6829 and #6831 (@Lstarsky0), and #6830 (@SparkofSpike). Resolve the 19 reviewed counterparts to the exact V22 product tree, including all 156 original translated values and the original localization regression test. Exact V22 local checks: Rust 1351/0/0; localization 54/0/0; CI-policy Clippy PASS. CLI: 3 actual processes / 6 checks / 6 local fixture requests / 0 paid calls; approval, resume, cancellation and EOF effects passed. npm test + check:web: 1180 passed / 0 failed / 7 explicit skips (wrapper101, SDK19, host378, website682); strict TypeScript and production web passed. No contributor harvesting, runtime default flip, install or release claim. Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Hmbown
pushed a commit
that referenced
this pull request
Oct 4, 2026
Windows Native hosts: on 02fcc3e the LPAC token check and the data-directory share conflict were fixed, and the isolation probe ran inside the LPAC for the first time. Node then aborted at startup (WSAStartup 10107): an LPAC cannot open any registry key without the registryRead capability, and Winsock reads its catalog from the registry. Native hosts now receive exactly that one capability (derived by name), and the token check requires exactly it; it grants no file, network or COM access, and socket creation stays denied, which the probe checks. Bun failed opening the NUL device (EPERM) for --config=NUL: the plain Bun host now reads an empty config from the granted runtime-copy directory, and the Windows compiled host relies on --no-compile-autoload-bunfig instead of baking --config=NUL. Unprotected file ACL edits now pass an explicit-only DACL to SetSecurityInfo with UNPROTECTED_DACL_SECURITY_INFORMATION so Windows re-derives inherited entries from the parent (a file has no children to propagate to); the kernel write had turned a file's inherited entries explicit. ACL pointer reads use checked NonNull access (CodeQL rust/access-invalid-pointer on 02fcc3e). Windows atomic writes: Fleet's WorkspaceFile/WindowsDirectory pins, new in 0.10.1, keep every ancestor directory of a Fleet file open with read-only sharing. MoveFileExW (tempfile::persist) reopens the destination directory with FILE_ADD_FILE, so while a Fleet ledger is alive (a whole `codewhale fleet` run, or a Runtime API request) Codewhale's own atomic writes into the workspace root or its ancestors failed with os error 32. That includes file-tool edits; hosted Windows showed it as a bare 500 writing mcp.json. On Windows, write_atomic now creates its temp with DELETE access and renames through that handle with a bare file name (the rename Fleet publication already uses), so the parent is never reopened and no pin is relaxed. Names Windows would rewrite (trailing dot or space, device names) are refused before any temp exists, and every failure path closes the delete-denying handle before removing the temp. MCP config write errors now name the file. A Windows test writes and replaces a file beside live Fleet pins and checks refused names leave no temp behind. Wire JSON: the extension-host `isJson` guard used Array.every and Object.values, so it accepted sparse arrays, extra array properties, accessors and symbol keys that serialize differently from what was checked (Copilot review on #6815). It now accepts only dense arrays and plain objects whose own keys are enumerable string data properties, the rule storage.ts already enforced; storage's duplicate check is removed. A new test fails on the old guard and passes on the new one. Bundles that include the guard were rebuilt with the pinned esbuild; the harness builtin digest pin in tier.rs moves with it. Release notes: credits and entries for #6820, #6829, #6830 and #6831, which landed in 0.10.1 without CHANGELOG coverage, and for #6827 (Windows node.exe kills are held by the built-in safety floor even in Full Access), crediting @jayanthvee in the CHANGELOG, docs/CONTRIBUTORS.md, website credits and public-surface facts. Fixes #6827 Source15 verification (3,792 rows; owning HEAD cf03333 and index 5983aa54 unchanged): - npm test and npm run check:web: 1,185 passed / 0 failed / 7 explicit skips (the website credit-parity test caught the first draft missing the new reporter credit); extension-host suite 390 tests, 383 passed, 0 failed, 7 skipped. - macOS, compiled host rebuilt from the new bundle: extension_host 177/0, plugins::install::dsh 28/0, mcp 407/0, utils 38/0, tools::file 190/0, runtime_store_convergence 14/0, builtin digest table 2/0. - Windows: cargo check --target x86_64-pc-windows-gnu of codewhale-tui lib and tests clean under deny(warnings); write_atomic change reviewed adversarially (FIX_FIRST findings applied: early-error temp cleanup, single retry layer, rewritten-name refusal). The LPAC capability, Bun config and file-ACL changes are type-checked only; their runtime proof is this head's hosted Windows run. Hosted 02fcc3e: Safety, Lint, npm wrapper smoke and Test (ubuntu-latest) passed. Windows 17,952 passed / 91 failed: LPAC runtime startup (Node WSAStartup, Bun NUL config), one file-ACL hygiene test, the mcp.json write conflict and one DSH HTTP case behind the probe, all addressed above. CodeQL flagged five pointer reads, addressed above. Not proven here: Windows runtime of these repairs. This is source integration, not release, deploy, provider or install approval. Evidence: artifacts/gpt61-0101-takeover-20261002/parent-source15-application, parent-source15-local, parent-source15-npm-web-actual, windows-gnu-check. Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Summary
Follow-up to the pinned user-prompt header: it now tracks the turn the
viewport starts on instead of only the newest message, and clicking it
returns the viewport to the message it names.
message alone: scrolling up past that message dropped the header
entirely, and it only came back once the viewport cleared the whole
turn. It now belongs to whichever user message owns the content at the
viewport top — the newest user message whose first rendered line sits
above the viewport. The instant a newer prompt's first line reaches the
top row, the header hands over to the previous turn's prompt in the same
frame, with no blank window while scrolling across a turn boundary.
the message it names. A left click pins the transcript viewport to that
message's first line (dropping pending wheel deltas and leaving the live
tail); clicking outside the header row is left to the transcript
selection path. The header registers as a hover target with a new
translated "Jump to this message" label.
Changes
crates/tui/src/tui/widgets/mod.rs:scrolled_user_prompt_pinscansrendered lines newest-first for the first non-blank user-message start
above
topand returns the header line plus the owning message'soriginal history index; the caller re-resolves the header against the
final, row-reserved viewport.
crates/tui/src/tui/app.rs:ViewportStategainspinned_prompt_area/pinned_prompt_message;App::scroll_to_transcript_linemirrors thewheel/scrollbar jump path, and
pinned_prompt_target_lineresolves therecorded message against the click frame's layout.
crates/tui/src/tui/mouse_ui.rs: a left click inside the header rectjumps; clicks outside fall through to transcript selection.
crates/tui/src/tui/ui/frame.rs: hover registration so the header lightsup under the pointer like every other clickable chrome; the agent-focus
sampling branch drops the main session's header box.
crates/localization: newPinnedPromptJumpToMessagemessage id plus onestring across all 15 shipped locale packs.
Review follow-up
Two independent reviews were posted on the fork PR (SparkofSpike#5), both
closing as mergeable; every finding was addressed before merge.
the pin target and then failed the first-line render check, dropping the
header instead of handing over to an older message — prompts without a
renderable first line are now skipped during the scan, with a regression
test. It also asked for multi-line and non-identity
collapsed_cell_mapcoverage, which was added, and confirmed that the header's read
resolution against the click frame's layout is intentional.
pinned header's hit box even though the focus pane paints no header (the
focus banner row became an invisible click/hover target — now dropped),
and that reserving the header row moved
topdown on the tail so aprompt whose first line was exactly the full-height top row could be
hidden behind a header naming an older prompt (the header is now
re-resolved against the final viewport, with a regression test). It also
asked for the header to key off a message identity rather than a
frame-bound line offset, and for an end-to-end render→click→land test —
both are in.
verifying each fix point by point.
Base and CI note
main(ad4325063), so it sits on thecurrent tree — that commit is also the rustfmt fix for
crates/tui/src/child_env.rs, which makescargo fmt --all -- --checkclean repository-wide.
Lintjob's clippy step may still fail on three findings thatlive on
mainand are untouched here:child_env.rs:718(
chunks_exactconstant chunk size),mcp.rs:290andlib.rs:13797(
needless_return). Every file this PR touches is clippy-clean underthe CI allow list.
Type of Change
Testing
cargo fmt --all -- --check— clean repository-widecargo check -p codewhale-tui --all-targets— exit 0cargo clippy -p codewhale-tui --all-targets --locked -- -D warnings -A clippy::uninlined_format_args -A clippy::too_many_arguments -A clippy::unnecessary_map_or— no findings in any file this change touches (the three remaining errors are the pre-existing ones noted above)cargo test -p codewhale-tui --lib -- pin_helper→ 7 passed; 0 failed (hand-over timing, blank-led skips, reserved-viewport repin, filtered-map resolution)cargo test -p codewhale-tui --lib -- pinned_prompt→ 6 passed; 0 failed (header layout & tail reservation, hit-box recording, click jump, click outside the row, hover registration, render→click→land)cargo test -p codewhale-tui --lib -- hover_target→ 2 passed; 0 failedcargo test -p codewhale-localization→ 52 passed; 0 failed (key-parity gates across all packs, including the new message id)path was verified live; the hand-over timing was iterated on live
session feedback and is pinned by the unit tests above.
Checklist
hand-over semantics and the click path)
(no external contribution in this change)
Related Issues
No-Issue: interaction follow-up to the pinned prompt header; no upstream
issue was opened for this.
Attribution
🤖 Generated by SpikeBot 000(CodeWhale-LOCAL)