Skip to content

Fade overflowing sidebar labels - #415

Merged
wingleeio merged 10 commits into
zeronsh:mainfrom
gaelcado:fix/sidebar-text-fade
Sep 17, 2026
Merged

wingleeio merged 10 commits into
zeronsh:mainfrom
gaelcado:fix/sidebar-text-fade

Conversation

@gaelcado

@gaelcado gaelcado commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Replace ellipses on overflowing sidebar labels with a 20 px right-edge fade: active and archived session titles, branch names, project/device metadata, project-filter labels, and device group headings. Fitting labels remain opaque except for the existing vertical scroll fade.

Ease the right-edge fade into view as overflow grows. Preserve search highlighting, adjacent controls, branch/PR spacing, and the sidebar and command palette's vertical fades. Label fades inherit the active scroll container's vertical bounds and asymmetric fade bands; paint scopes are restored before siblings render. This fixes the reviewed regression where long labels stayed bright at vertical scroll edges.

Merge main while retaining both faded disclosure labels and the shared sidebar separator introduced by #407.

The existing renderer override remains pinned to gaelcado/zui@53869c204efb866d19af292cab8b1773898eeedd. Its entire source tree is identical to upstream zeronsh/zui@1561532176f54262e360acbb8bc00c6fcf183975 from merged zeronsh/zui#12. Migrating away from the override also requires aligning gpui-base's GPUI dependency pin.

Validation at cd247d721113a71065c2e4ca1ba92877beb78a9e:

  • All 1,059 UI tests pass locally, including a new paint-level regression for nested fades, overflow transitions, asymmetric bands, and sibling scope restoration.
  • Linux/X11 production Shell fixture rebuilt and inspected with synthetic sessions. Fitting and overflowing bottom-row title prefixes match pixel-for-pixel; overflowing labels retain their horizontal fade.
  • Changed Rust files pass rustfmt; diff whitespace checks pass.
  • Fresh screenshots are attached to the approval review. All executed cross-platform CI checks passed before merge.

@gaelcado gaelcado changed the title Fade overflowing sidebar session titles Fade overflowing sidebar labels Sep 16, 2026
@gaelcado
gaelcado marked this pull request as ready for review September 16, 2026 21:35

@wingleeio wingleeio left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security audit and review of f7f73bd77cce890fdb837cb364d01c427a8607bb: requesting changes for the nested-fade rendering regression described inline. No actionable security vulnerability found in the reviewed change, but this revision should not merge yet.

Security scope: inspected the UI diff, all changes in the pinned renderer versus the previous renderer, dependency provenance, and shader/host data flow. The full source tree of fork commit 53869c204efb866d19af292cab8b1773898eeedd exactly matches merged upstream commit 1561532176f54262e360acbb8bc00c6fcf183975 (tree e5f21c24b5c7a161cb80b6a2c58c1a8c8382b065). No added application network access, command execution, authentication changes, or new unsafe Rust was found. The immutable renderer pin is unchanged in the tested candidate.

Validation and conflict handling:

  • Prepared a local merge with main at b4dd24d7346a50fe73658d06e4d75ddb9a61c50e. Resolved the disclosure-header conflict by keeping both this PR's faded label and main's shared sidebar_separator helper. Nothing was pushed.
  • On that locally resolved candidate, cargo test --locked -p zeron-ui --lib -- --test-threads=1 passed 1,058 tests, 0 failures. Changed Rust files pass rustfmt and the diff passes whitespace checks.
  • Built and ran an isolated Linux/X11 production Shell fixture with synthetic sessions. Two otherwise identical 1100×440 windows differ only in whether titles fit or overflow horizontally. The overflowing Session 04 remains fully bright at the bottom scroll edge; the fitting Session 04 correctly fades. The adjacent icon still fades in both cases, making the inconsistency visible.
  • Existing PR CI and the pinned renderer's Windows CI succeeded. Those tests do not cover nested horizontal/vertical fades. The renderer's WGPU unit test cannot be invoked directly through the application's workspace because it is a dependency with its own dev-dependencies; no new local shader-test pass is claimed.

Fresh GitHub user attachments from the controlled fixture (look at the bottom Session 04 row):

Overflowing labels: vertical fade is lost

Overflowing labels: vertical fade is lost

Fitting labels: vertical fade remains active

Fitting labels: vertical fade remains active

Comment thread crates/ui/src/shell.rs

@wingleeio wingleeio left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed and re-audited cd247d721113a71065c2e4ca1ba92877beb78a9e. The original nested-fade finding is resolved; no remaining actionable security or correctness findings.

The conflict resolution preserves both the faded disclosure label and main's shared sidebar separator. The only additional implementation change retains the active wrapper fade during painting, keyed by window, and carries its vertical bounds and independent top/bottom bands into overflowing label fades. Fitting labels inherit the original parent scope; paint state is restored after each child. Interior mutability avoids scheduling global-observer notifications for each painted label. No dependency revision, network, command execution, authentication, or unsafe-memory changes were added by the fix. The pinned renderer source tree remains identical to the previously audited upstream merge.

Validation:

  • Full local UI suite: 1,059 passed, 0 failed.
  • New paint-level regression exercises fitting → overflowing → fitting behavior through repeated width changes, top-only/bottom-only/combined/no vertical fades, asymmetric bands, and restoration for siblings and elements outside the scroll container.
  • Rebuilt and reran the Linux/X11 production Shell fixture that exposed the bug. The bottom-row Session 04 prefix now matches pixel-for-pixel between overflowing and fitting titles (x=86..152, y=469..484), while long text retains its right-edge fade.
  • Changed-file rustfmt and diff whitespace checks passed. No intervening PR or main changes were found before applying this fix.

Fresh GitHub user attachments from the fixed build, using isolated synthetic sessions. Cross-platform CI is running on the pushed head at review submission; these screenshots are Linux fixture evidence.

Fixed overflowing title: horizontal and vertical fades both apply

Fixed overflowing title: horizontal and vertical fades both apply

Fitting title: matching vertical fade at the bottom edge

Fitting title: matching vertical fade at the bottom edge

@wingleeio
wingleeio merged commit 01b705f into zeronsh:main Sep 17, 2026
11 checks passed
@wingleeio wingleeio mentioned this pull request Sep 17, 2026
hoangvu12 pushed a commit to hoangvu12/roboco that referenced this pull request Sep 22, 2026
Upstream: zeronsh/zeron 01b705f
"Fade overflowing sidebar labels (zeronsh#415)"

Ticket 15 of the 2026-09 upstream-ports program.

Desktop (cherry-picked, conflicts resolved by intent across the rebrand):
- edge_fade.rs: fade_label_overflow — a right-edge fade that eases in as a
  label's overflow grows from zero to one band (label_fade_outset's
  smoothstep), unlike scroll chrome which snaps at 1px; the paint-time
  PaintFades stack keeps a label's wrapper scope alive so an overflowing
  label inherits its scroll container's vertical fade (window-scoped, so a
  nested draw of another window never leaks it); both new tests land
  (painted_label_retains_scroll_fade_across_overflow_transitions,
  label_fade_enters_continuously_and_settles_at_one_band).
- shell.rs: sidebar_faded_label wraps the chat row's device line, title,
  and branch — nowrap content behind a tracked overflow-hidden wrapper.
- shell/spaces.rs: the disclosure header label, the spaces-filter label +
  device tag, and the archived shelf titles adopt the same wrapper.

Exclusions (per AGENTS.md GPUI-pin rule):
- The Cargo.toml hunk adding [patch."https://github.com/zeronsh/zui"]
  gpui* = gaelcado/zui@53869c20… ("temporary renderer override for the
  companion per-pixel text fade PR") is DROPPED, along with its Cargo.lock
  churn: roboco stays on hoangvu12/zui (patch rev == top-level pin). The
  label fade needs no gaelcado-only gpui API — EdgeFade/with_edge_fade/
  Global/WindowId all exist at our pin; only the renderer's text opacity
  granularity differs (per-glyph, not per-pixel), so edge_fade.rs's module
  doc keeps roboco's "per-glyph granularity" wording. If the per-pixel text
  fade lands in hoangvu12/zui later, both pins move together per AGENTS.md.
- The shell.rs/spaces.rs hunks' popover::search_highlight(…) label content
  is CONTEXT roboco does not carry (it rides 74558a2, ticket 16): the
  faded wrappers wrap roboco's plain label children instead.

Web parity (web/packages/app, same commit):
- components/sidebar-faded-label.tsx: the mask-image right-edge fade —
  ramp width --rb-label-fade-inset, 0 while the label fits, eased to one
  20px band by label_fade_outset (the same curve, unit-tested); one shared
  module-level ResizeObserver measures every mounted label. Ancestor masks
  compose for free, so the sidebar's vertical scroll fade keeps fading rows
  inside an overflowing label (the free web peer of PaintFades).
- chat-list.tsx / archived-section.tsx / sidebar-disclosure.tsx /
  space-filter.tsx: the device line, chat title, branch, archived title,
  disclosure label, spaces-filter name and device tag become faded labels —
  the ellipsis truncation is gone (CSS guards in the test).
- app.css: .sidebar-label-fade/.sidebar-label-fill/.sidebar-label-fade-inner;
  the label classes drop text-overflow: ellipsis.

Tests: roboco-ui edge_fade 2 tests pass. Web: sidebar-fade 7 (2 new label
tests + the CSS guards), sidebar-view/archived/sidebar-store/sidebar-tween/
sidebar-tooltip 54, picker-search 17 all pass; tsc --noEmit clean.
wingleeio added a commit that referenced this pull request Sep 24, 2026
* Refine Files panel toggle with a custom tree icon

* Move Files search into the panel titlebar

* Refine Files tree icon geometry

* Fix command palette session row arguments

* Add theme-aware indentation guides to file trees

* Add file browser button to diff file headers

* Make file tree titlebar search adapt to narrow panels

* test(ui): reproduce activity replay after batched transcript catch-up

* Color file tree entries with shared remote-safe Git status

* feat: add Antigravity ACP, improve context UI, and persist window geometry (#349)

* feat: add antigravity agy harness with grouped reasoning models

drive google's agy cli over its own stream-json print mode: one process
per session with prompts written to stdin, step updates normalized into
text, tool and context-usage events, and the terminal result frame as
the turn end. steers queue for the next turn, interrupts signal the
process, and resumes reopen the conversation with --conversation.

agy lists every effort as its own model id, so variants are grouped into
one model with a low/medium/high ladder and the picked level is folded
back into the variant id at run time.

headless agy cannot prompt for permission, so sessions run in
accept-edits mode unless auto-approve is on, and denied actions surface
as an error explaining how to allow them.

wires the harness through the proto id, engine registry, account slugs,
desktop pickers and settings, and the ios catalog and brand mark.

* fix: always skip agy permissions and report context windows

zeron has no approval ui and headless agy auto-denies anything it would
prompt for, so runs always pass --dangerously-skip-permissions, matching
the claude and codex harnesses. denied actions can now only come from
agy's own deny rules, and the error says so instead of pointing at a
missing auto-approve toggle.

agy reports token counts but no context window, so context usage now
carries the published window for the gemini, claude and gpt-oss model
families, leaving it unreported when agy picks its own default model.

* fix: count cached agy tokens and fit the context window tooltip

once prompt caching kicks in agy moves the cached prefix out of
input_tokens into cache_read_tokens, so the context indicator dropped
and climbed between steps. context usage now reports their sum, which
grows steadily across a run.

the context window tooltip was fixed at 260px regardless of its text, so
it now sizes to its content up to that width and groups token counts by
thousands.

* feat: list antigravity skills as slash commands

zeron showed no slash commands for antigravity. commands now come from
agy's own `-p=/skills` json listing, which answers without a model turn,
covering built-in and global skills. names are deduped in listing order
and descriptions trimmed to their first sentence for the picker, and a
non-empty listing is cached like the model catalog.

agy's cli commands such as /usage and /model are refused under
--input-format stream-json, so they are not offered. the listing runs
from home because the command list is not scoped to a session, so
workspace skills are not listed but still expand when typed.

* feat: drive antigravity over its acp server with sign-in on enable

replace the agy stream-json driver with google's antigravity acp server
(agy_acp_server 1.1.1) on the shared acp harness. the pinned release
archive for the platform downloads and unpacks once into the managed
adapters dir, reusing the npm installer's atomic marker and lock.

antigravity is now off by default. turning it on in settings runs the
server's google sign-in from home, outside any project, so preview
discovery never consumes the one-shot oauth redirect; the app opens the
single sign-in tab from the polled url and the toggle flips only once
sign-in succeeds. turning it off signs out through acp logout, and a run
without a login points to settings instead of opening a browser.

effort variants group by their display name, since a signed-in catalog
pairs gemini-3.1-pro-low with gemini-pro-agent for high, and each level
sends the id the server advertises. skills from the global gemini skill
folders are listed as slash commands next to the server's own, with
logout hidden. the context indicator is hidden until a window is
reported, and its tooltip no longer clips wrapped text.

* fix: address antigravity review feedback

* feat: add phased sign-in feedback for antigravity setup

* fix: read antigravity auth settings the way the server does

resolves the three auth-settings findings from the pr review: expand a
home-relative GEMINI_HOME like the server's os.path.expanduser, parse
settings.json as hjson since the server reads it with hjson.load, and
canonicalize the vertex-ai alias to the advertised agent-platform id.

* test: pin antigravity's live and fallback model catalogues

covers the review's catalogue recommendation: a newer flash the signed-in
account advertises reaches the picker as its own grouped row, while the
offline fallback stays on the models the pinned 1.1.1 archive bundles.

* feat: persist window geometry and restore its display

* fix: persist screen-sized macOS window geometry

* fix: align Antigravity auth settings paths with its server

* fix(transcript): skip replay animations for historical activity

* Add configurable shortcut to open model picker (#433)

Co-authored-by: wing-anara <wing@anara.com>

* Fix token refresh storms and preserve sessions during transient DNS failures (#352)

* fix(auth): share refresh attempts and bound retry cooldown

* fix(auth): keep transient token failures distinct from sign-out

* fix(engine): preserve DNS and HTTP transport error causes

* fix(transcript): track replay incrementally and preserve live animations

* Polish command palette and add quick theme action (#407)

* Polish command palette layout and add theme action

* Polish palette content spacing and action accessibility

* Reuse sidebar separator and refine palette search icon

* Dim the workspace behind the command palette

* Use Solar sun and moon icons across appearance controls

* Make command palette section separator full width

* Suppress unflagged Enter repeats in command palette

* feat(ui): add configurable conversation width in appearance settings

* fix(transcript): retain opening history across replay updates

* Fade overflowing sidebar labels (#415)

* Fade overflowing sidebar session titles

* Extend sidebar fades to branch and device labels

* Slightly strengthen sidebar label fades

* Widen sidebar label fades to 20 pixels

* Smooth sidebar fade onset and use per-pixel text rendering

* Add reproducible sidebar CPU comparison and supplied preview

* Document measured sidebar fade CPU comparison

* Keep sidebar fade PR focused on behavior

* Preserve vertical scroll fades inside overflowing labels

---------

Co-authored-by: wing-anara <wing@anara.com>

* Release v0.2.73

* Fix truncated Cursor catalogs and refresh harness models (#436)

Co-authored-by: wing-anara <wing@anara.com>

* Add collapsible pinned sidebar section with animated divider

* chore: release v0.2.74

* Fix keyboard focus when opening the model selector (#438)

Co-authored-by: wing-anara <wing@anara.com>

* chore: release v0.2.75

* Add animated drag transfers between pinned and regular sessions

* Remove sidebar section drag highlights

* Simplify pinned and archived section headers

* Right-align pinned and archived disclosure chevrons

* Reduce spacing above archived sessions

* fix(cursor): recover abandoned runs and stabilize model discovery

* fix(ui): align elapsed timer with working indicator text

* fix(ui): format elapsed time in hours and days

* test(cursor): stress steering bursts and prioritize cancellation

* chore: release v0.2.76

* Fix blank session revisits and transcript attachment race

* Show a bounded local transcript tail before rebuilding whale history

* Verify opening previews and cached revisits never replay tool animations

* Prevent whale replay from starving desktop networking

* Prepare whale transcript presentation off the UI thread

* chore: release v0.2.77

* Prevent replaying sidebar movement after successful drops

* Reconcile sidebar pins against authoritative registry snapshots

* Validate sidebar pin changes consistently before accepting drops

* Serialize optimistic pin writes and reconcile acknowledged state

* Exercise pin write transport and migration persistence failures

* Clear pin write notices after successful recovery

* Sync sidebar pins with per-item ordering keys

* fix(cursor): preserve SDK failure diagnostics and update to 1.0.31

* test(cursor): verify token refresh against aged live SDK sessions

* ci(cursor): automate SDK updates and gate releases on auth compatibility

* Preserve Cursor user context through steering and startup interruption

* chore: release v0.2.78

* feat(ui): add configurable compact sidebar and project icons

* Refine sidebar accordions and compact row layout

* Reorder sidebar icons and use terminal remote icon

* Render archived sessions with shared sidebar data and layout

* Let sidebar titles use empty action space

* Use frosted project monograms and refine sidebar action icons

* Refine project badge colors and open sidebar options to the right

* Add compact transcript mode: one collapsed work accordion per turn

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* Select project monograms from a fixed curated palette

* Use Earth icon for remote sessions

* fix(actions): bound project file reads and reject special files

* Discover monorepo project icons and default to compact sidebar

* Rename sidebar location option and update globe artwork

* fix(actions): preserve project identity for queued worktree setup

* Improve monogram hover contrast and show project tooltips

* Show compact-mode "Worked for Xm Ys" after the turn settles

Stamp durationMs on the assistant entry at segment finish and, in compact
mode, fade that into a subtitle under the work accordion when the live
working trailer goes away.

* Simplify project icons, add device tooltip, and split compact mode

- Drop monorepo icon discovery; lookup checks root-level artwork only.
- Project icon tooltip uses the pull-request badge card and shows the
  owning device name under the project name.
- Selected rows keep the monogram's hover tint without hovering.
- Remote session icon uses the Solar "global" glyph.
- View options menu shows Compact mode in its own Layout section.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Match archived "Show more" height to compact rows

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Persist compact-mode turn duration and replace the work summary

Stamp and recover "Worked for" duration across relaunch, then crossfade
the compact accordion title from the tool summary into that line once
the turn settles.

* Drop guessed compact durations and the turn-duration sidecar

Trust durationMs plus the in-session live timer. Do not infer Idle
updated_at, do not rewrite compact-turn-durations.json, and do not
resync the transcript every second while Working.

* chore: release v0.2.79

* Remove Cursor SDK diagnostics from device settings

* Expand compact "Worked for" into the normal transcript layout

Collapsed compact mode still hides the turn behind the work header.
Opening it now reveals thinking, tools, and narration as ordinary
transcript rows instead of "Wrote" chips. The final reply stays
outside the toggle.

* Make the explorer a docked portion of one right pane

The explorer column and the surface host now form a single right pane
under one shared header. The explorer toggle docks or undocks its
portion, opening the pane with only the explorer when the pane was
closed. The pane toggle (outermost, like the left sidebar's) closes both
portions and reopens whichever were visible before, defaulting to the
surface host. Programmatic opens (files, browser links, subagent chips)
go through set_surfaces_open so they never close a pane the user has
open. The header carries the explorer seam hairline and the rightmost
column carries the window corners.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Let the pane toggle drive only the surface host

The right-pane toggle now opens or closes just the surface host. With
only the explorer docked it opens the surface host beside it, and it
never hides the explorer: undocking is the explorer toggle's job alone.
Closing the last surface tab collapses the surface host, leaving a
docked explorer to keep the pane open on its own, or closing the pane
entirely when nothing else is docked.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* chore: ignore agents.md

* chore: ignore .agents directory

* ios: fix transcript follow, normalize model catalogs, desktop networking parity (#468)

* ios: normalize model catalogs, verified cursors, 300s checkpoint deadline

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ios: keep transcript follow alive across stale gestures and appends; opaque session header

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ios: 50-scenario transcript scroll matrix test

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ios: keep history anchor exactly in place during streaming

restore() clamped the anchor row to keep 44pt visible on every relayout,
so a row straddling the top edge by more than height-44 shifted the
reader's viewport whenever content below streamed in. Only apply the
clamp when the anchor row itself shrank (a fold collapsing).

Matrix: tail-gap threshold accounts for block trailing padding, pinned
offsets may retreat by measured content shrink, jump uses arm()+jump
like the button.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ci: rerun ios-tests

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Wing Lee <wing@anara.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* Give the explorer a secondary header for search and visibility

Move the file search field and the show-hidden eye out of the titlebar
and into a toolbar row inside the file pane, using the same toolbar band
the editor's breadcrumb header uses so both columns share one header
height. The titlebar explorer slot now carries only the explorer and
pane toggles; the compact/expanding titlebar search is gone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Compact sidebar account control and nest view options (#465)

* Use a compact avatar button for the sidebar account menu

* Match account button hover shape to circular avatar

* Size sidebar avatar to match remote session icon

* Nest sidebar view options in category submenus

* Separate sidebar Show options and use a Compact switch

* Share model selector hover intent with sidebar submenus

---------

Co-authored-by: wing-anara <wing@anara.com>

* Add custom sidebar sections with session drag and drop (#486)

Co-authored-by: wing-anara <wing@anara.com>

* chore: release v0.2.80

* Sync sidebar sections across devices (#487)

Co-authored-by: wing-anara <wing@anara.com>

* chore: release v0.2.81

* Add zeron mcp server with parent-linked chats

`zeron mcp` serves MCP on stdio and proxies every tool into the running
engine's localhost IPC, so an agent in one chat can create, read, message,
wait on, interrupt, and archive other chats. The protocol layer is
hand-rolled (initialize/ping/tools/list/tools/call over newline JSON-RPC)
to avoid a new SDK dependency.

Chats created through the server record the creating chat as parent
(`Chat.parent_chat_id` / `parentChatId` on the registry row, serde
defaulted so older rows read as parentless). `list_chats { parent }`
returns a chat's children. The left sidebar, project tabs, jump slots and
Archived section hide chats that have a parent; they stay reachable by id,
deep link, and MCP.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Add Mod+E files-panel shortcut and space the pane toggles

The explorer's own toggle (the titlebar tree button) gets a customizable
shortcut, Cmd+E on macOS and Ctrl+E elsewhere, listed under Panels in
Settings > Shortcuts. It docks or undocks the explorer portion of the right
pane and never touches the surface host, matching the button. A settings
file written before this shortcut existed keeps a custom binding that
already used the chord; the new row then arrives unbound instead of
double-bound.

The explorer toggle and the pane toggle rendered edge to edge as one fused
block. The slot now carries the same 4px gap the surface strip keeps
between its controls, and the reserved slot width grows to match.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Drop the doubled hairline over the explorer seam

The explorer column is padded down by the titlebar height and its left
border already runs through the header band. The header's explorer slot
drew the same hairline on the same pixels, and the stacked alpha read as a
lighter line than the seam below it. The slot no longer draws one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* ios: durable outbox + send watchdog, fix transcript scroll jumps, session UX polish (#479)

* ios: durable chat2 outbox, send watchdog, split backfill deadlines

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ios: keep realized heights across transcript updates, diff rows instead of reloadData

UITableView drops every measured height on reloadData/endUpdates and falls
back to the 140pt estimate, so a long transcript's content size collapsed and
re-expanded under the finger on each structural update — the visible jump
while reading history. Cache measured heights by row id and serve them as
estimates, apply structural changes as insert/delete batches (falling back to
reloadData above 400 changes), and only apply the 44pt fold clamp in anchor
restore when the row's content version actually changed, not when a hosted
cell settled its own measurement. Restore outbox pushes in order on startup.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ios: center jump-to-latest, fade composer chips, show connectivity in session strip

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ios: grow composer shell with multi-line draft under software keyboard

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ios: bound session stores and harden chat2 durability

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ios: make animated jump-to-latest realize the tail first and self-correct

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ios: dial pending-outbox stores past the warm cap, make stop() terminal, real-store durability tests

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ios: export snapshots off the main thread on background flush (0x8BADF00D watchdog)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ios: retire armed debounce/retry timers when a background flush starts

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ios: retire saver timers up front, keep background flush sequential

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Wing Lee <wing@anara.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* Separate Antigravity detection and authentication from server availability

* Make Antigravity enablement follow detection and expose explicit sign-in

* Record Antigravity validation status and disk-limited follow-ups

* fix(acp): own process groups and preserve Pi crash context

* fix(pi): preserve descendant cleanup grace and verify durable resume

* Remove repository-local validation status report

* fix(acp): reject requests after EOF and retain the latest stderr tail

* ios: bound snapshot write cadence and store residency by bytes (#490)

* ios: bound snapshot cadence and residency by bytes

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ios: guard deferred snapshots against stale store ownership

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* ios: keep eviction flush alive after store dealloc

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Wing Lee <wing@anara.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* Consume complete HTTP request headers in catalog test fixtures

* Let the engine surface Antigravity launch errors uniformly

* Allow Antigravity cold discovery up to ninety seconds

* fix(harness): detect current OpenCode server versions and auth failures

* fix(harness): version OpenCode commands and surface HTTP rejection

* feat(harness): select OpenCode agents through cached model options

* fix(harness): normalize OpenCode status retry and tool progress events

* docs(harness): record OpenCode compatibility and extend isolated probes

* Drop reference-integration name from ACP comments

* fix(harness): select newest CLI and honor configured model metadata

* fix(harness): finish portable version probes and diagnostics

* fix(harness): retain catalogs by credential and binary context

* fix(engine): persist contextual model catalogs and refresh in background

* fix(ui): retain model rows after refresh errors and send force

* feat(claude): share initialize discovery for live models and commands

* fix(models): classify discovery failures and reject unauthorized stale catalogs

* fix(codex): reject empty catalogs and retire discovery children

* fix(ui): preserve saved models absent from refreshed catalogs

* test(harness): align refresh regression with last-good catalogs

* test(opencode): retain same-context catalogs on empty refresh

* docs(models): record full validation and live discovery results

* fix(harness): own archive adapter temporary roots through shutdown

Port the scratch guard from upstream #475, retaining process-group shutdown and limiting roots to resolved archive launches. Add a managed live-probe mode.

Co-authored-by: LoikStyle <131105263+LoikStyle@users.noreply.github.com>

* fix(engine): allow remote adapter catalog discovery to finish

Co-authored-by: laurentcodes <stlaurentcodes@gmail.com>

* fix(harness): strip echoed wakeup blocks from Antigravity streams

Port upstream #452 streaming filter and chunk-boundary regression coverage.

Co-authored-by: laurentcodes <stlaurentcodes@gmail.com>

* test(harness): prove cancel notifications omit request ids

* test(harness): preserve large frames amid stdout noise and CRLF

* test(harness): drain a full update queue before turn completion

* test(harness): empty assistant chunks produce no segment events

* fix(harness): retain bounded startup command and mode metadata

* fix(harness): reject foreign session permissions and ignore their traffic

* fix(harness): redact credentials in crash diagnostics

* fix(harness): discard prompt settlement after cancel escalation

* test(harness): dropping an idle stream reaps its warm adapter

* fix(harness): configure Antigravity siblings and capture stdout sign-in URLs

* test(harness): exercise Pi steering without the extension

* fix(harness): redact quoted and whitespace-padded credentials

* fix(harness): bound OpenCode submission and confirm ambiguous idle turns

* fix(harness): make scratch roots private and retain guards during cancellation

* style(harness): format adapter regression tests

* fix(harness): ignore JSON objects that are not RPC responses

* test(harness): expose event status in the OpenCode HTTP fixture

* refactor(harness): name the stdout observer callback type

* fix(harness): require explicit Antigravity installation

* feat(settings): install Antigravity explicitly on the selected device

* test(harness): expose Antigravity detection in the live probe

* fix(opencode): version permission reply bodies at 2.0.4

* fix(opencode): bind both task and subagent spawn tools

* test(opencode): allow explicit permission answers in the live probe

* test(engine): handle partial archive request headers

* test(engine): require the Antigravity server for enablement

* Bump version to v0.2.82

* Add rich composer references and completion

* Fix rich-reference recovery for Cursor

* Validate portable rich invocation delivery

* Preserve OpenCode command intent through delivery

* Stabilize adaptive composer menus

* Verify Cursor rich-reference recovery envelopes

* Document rich composer visual evidence

* Preserve commands and skip unreadable skills

* Gate composer references and harden discovery

* Improve command discovery and mention chips

Share workspace command probes across catalogs while refreshing
between opens, and refine composer chip styling and layout.

* Refine Composer Mention Chips

* Refresh rich composer screenshots and review notes

* Move composer completion preferences to Shortcuts for active agents

* Animate the compact work fold's body under TOOL_FOLD

Toggling the "Worked for" shell used to sync() immediately, so the folded
rows popped in/out at full height instead of folding like every other
transcript expander. Body rows now stay mounted through the 140ms ease-out
tween: each sibling clips to a shared height budget (lerp from the
measured total toward the new target), a prepaint probe keeps row heights
current, and a settle sweep drops the rows once the retention window
elapses. Reversals seed `from` with the budget in flight so mid-tween
toggles continue smoothly, and reduced motion transitions instantly
without retaining the body.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* Fix rich composer review regressions

* Correct composer completion settings documentation

* Clarify Harness Completion Settings Documentation

* Add explicit platform-aware agent CLI installers

* Route and cancel explicit installs on the selected device

* Offer Install and Cancel for every eligible agent

* Document audited agent installation commands

* Preserve device switching and manual installation hints

* Install OpenCode 2.x from @opencode/cli when npm is the fallback

* Restore simple reference chips and trim composer review artifacts

* Consolidate composer and reference test fixtures

* Bound skill discovery and reject special files

* Refresh completion catalogs and harden pasted references

* Fix Add action button hover corners

* Bump version to v0.2.83

* fix(files): keep explorer available for archived chats (#500)

* Apply the conversation width setting to the composer (#453)

* fix(ui): align composer with configurable transcript width

* fix(ui): smooth composer reflow during dock transitions

* fix(ui): preserve composer width in narrow panes

* Replace Opus 5 with Opus 5.5 in the Claude catalog

Claude Code 2.1.280 ships claude-opus-5-5 (and claude-opus-5-5[1m]) as the
current Opus, demoting Opus 5 to a previous version. Swap the curated row
so the bare `opus` alias resolves to Opus 5.5, mirror the CLI's picker
copy, and update the label-pinned discovery/normalize tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Fix reduced-motion dock test after the snap_reflow merge

PR #453 added DockFrame::snap_reflow (set whenever motion is reduced) and
3c7185b added reduced_motion_cancels_panel_geometry_and_chrome_together
in parallel; each was green alone, but merged the test compares against a
settled frame without the flag and fails deterministically on main.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Bump version to v0.2.84

* Point the claude_models live-union fixture at Opus 5.5

The fake initialize response still resolved default/opus[1m] to Opus 5,
which no longer has a curated row after #505, so the union no longer put
claude-opus-5 second. Mirror what Claude Code 2.1.280 actually reports.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs: acknowledge The Context Company and invite sponsorships

* docs: remove redundant top-level sponsor links

* landing: swap troll tweets for real testimonials

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* landing: show GitHub star count on Star buttons

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* landing: star count next to the nav GitHub icon

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* landing: agent icons above the headline, add Used by developers from logos

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* landing: Supported by section with sponsor button under the main shot

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* landing: restyle Supported by as a quiet sponsor row

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* landing: remove Supported by section

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* landing: Used by logos rest in the harness-icon faint color

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(opencode): auto-approve tool permissions as a temporary workaround (#533)

* Bump version to v0.2.85

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Polish settings, providers and sign-in (#449)

* Redesign settings as a floating keyboard-accessible modal

* Align settings surfaces and controls with Zeron glass patterns

* Refine settings overlay material and page density

* Fix settings overlay stacking and reconstruct measured I/O switch

* Tighten settings navigation and reuse overflow edge fades

* Refine settings glass controls and remove render-time overhead

* Add dialog-contained dropdown positioning

Measure dropdowns after layout, constrain them to dialog bounds, and flip above the trigger when needed. Cover containment and long-menu scrolling with unit and GPUI tests.

* Polish settings controls and contain their dropdowns

Share modal bounds with dropdown placement, restore full-size appearance previews and icons, and group related settings with consistent spacing. Improve responsive rows and device cards, and use contained menus for theme, font, device, and title selectors.

* Refine settings navigation, material, and keyboard behavior

Match main-sidebar spacing, group settings under category headings, and move conversation behavior into its own page. Follow the command palette material and make Cmd+, toggle the modal without focusing its first entry. Add regression coverage for navigation, focus, and moved conversation controls.

* Tighten settings layout and refine glass controls

Remove redundant descriptions and the sidebar heading, separate notification groups, and constrain row metadata. Align appearance actions, group material choices, match dropdown chevrons, and replace beveled switches with tinted tracks and translucent thumbs.

* Update appearance copy tests for concise settings labels

* Protect frosted floating surfaces from backdrop contrast loss

* Keep settings descriptions and metadata readable on glass

* Render workspace command regression through the window lifecycle

* Restore thin light glass and original dark material

* Tune light frosted surface coverage

* Group agent access preferences in Settings

* Inline agent preferences and refine glass switches

* Preserve accent hue in light switch tracks

* Restore switch marks and contain settings chrome

* Align and strengthen switch state marks

* Use classic I/O proportions in settings switches

* Refine glass switches against I/O reference

* Match settings switches to selected material

* Tighten settings descriptions and row spacing

* Contain settings dropdown scrolling and refine controls

* Simplify agent details and polish device cards

* Unify settings actions and refine pill switches

* Refine settings switch and reorganize conversation controls

* Center switch marks in a wider track

* Unify settings tabs and retire hidden accounts route

* Refine settings close control and dark toggle accent

* Balance settings switch proportions and glass lighting

* Reduce settings switch thumb inset

* Unify settings choices and tighten conversation and device layouts

* Align device identity and actions in settings cards

* Use title case for settings sidebar headings

* Settings, providers and sign-in polish on top of the settings redesign

Settings
- Full-window settings page (Back at top, Esc/⌘, keep working), Cursor-style
  filled blocks, shared glass select for every dropdown, smaller switches.
- General tab (send key, compact mode, Escape, thread naming via the
  composer's model picker); Agents renamed to Providers.
- Devices page rebuilt on the block/row pattern.
- Sidebar footer: account name, settings toggle with active state.

Providers and accounts
- Compact account list with mini usage meters; the live account marked by
  an avatar ring, switching/removal in a ⋯ menu, optimistic switch/forget.
- Usage probes: concurrent, persisted stale-while-revalidate cache, only
  401/403 refreshes a token, Retry-After backoff, reasons instead of a bare
  "Usage unavailable"; Claude credentials read Keychain-first.
- One add-account flow for Claude Code, Codex, Cursor and Antigravity;
  Claude uses the CLI's loopback callback (paste-code is a fallback).
- Remote-device logins forward the callback port over the P2P mux, scoped
  to the login, the requesting device and its lifetime.
- `$` skills and separate `/` commands on by default.

Fixes
- Frosted/opaque switches no longer need a restart (the window's native
  backdrop update was dropped while that window dispatched the click).
- Single-flight usage/refresh markers released on cancel; login URLs open
  only for https or loopback; tunnel ports must be ≥1024 and match the
  authorize redirect; paste-code `state` no longer reuses the PKCE verifier;
  `/usr/bin/security` by absolute path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Build zui from zeronsh/zui instead of a contributor fork

The per-pixel text-fade renderer change is upstream as zeronsh/zui 1561532
(#12, tree-identical to the fork revision it replaces), so drop the
[patch] that redirected gpui/gpui_macros/gpui_platform/gpui_tokio to
gaelcado/zui and pin zui 1561532 directly. gpui-component moves to
5086ff4f, which pins the same zui revision, so the graph keeps a single
gpui.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Wing <wing@anara.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* Bump version to v0.2.86

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Honor system proxy settings in packaged desktop apps (#504)

* fix(network): honor system proxy settings

* Keep loopback HTTP off the system proxy

reqwest's system-proxy support has no loopback exemption, and macOS's
proxy bypass list is not consulted, so enabling it would route calls
to the local `opencode serve` (which carry its Basic-auth password)
through any machine-wide proxy. Build the opencode client with
no_proxy(), and fetch favicons for loopback pages directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Wing <wing@anara.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* Reopen Settings on the section last viewed (#541)

Generic ways into Settings (Cmd-, / Ctrl-,, the footer gear, the
command palette's "Open settings", /settings) now reopen the section
that was showing when Settings was last left, instead of always landing
on General. The section is persisted as `settingsSection` in
ui-settings.json through the shell's own settings copy, debounced like
other settings.

Links that name a section (open_settings(section), ZERON_OPEN_ROUTE=
settings/<section>) still open that section and become the remembered
one, as does switching sections inside Settings. A remembered section
that is unknown, hidden on this platform (Appshots off-desktop) or a
legacy alias (Agents -> Providers) reopens as General or its canonical
page. Deserialization is lenient: a missing, unknown or malformed value
reads as General without discarding the rest of the file.

Escape inside Settings still closes it, but only after closing what is
open inside it without holding focus: the footer account menu, the
device rename dialog, the add-account login flow on Providers, and the
theme import / mapping review dialogs. Previously an Escape with one of
those open (e.g. the login dialog, whose card never takes focus) closed
Settings underneath the dialog.

Supersedes #380, which did this against the previous settings design.

Co-authored-by: Wing <wing@anara.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* Retry the Windows identity lock through sharing violations (#527)

DeviceIdentityLock::acquire opens device-id.lock with share_mode(0) and
retries 200 times, but only on ErrorKind::PermissionDenied. When two
engine processes race for the lock, the losing open fails with
ERROR_SHARING_VIOLATION (raw os error 32), which Rust reports as
ErrorKind::Uncategorized, not PermissionDenied. The retry guard never
matched it, so the race failed engine startup outright instead of
waiting the intended 5ms.

The guard now also matches the raw ERROR_SHARING_VIOLATION code.
acquire_retries_through_sharing_violations holds the lock file with
share_mode(0) for 50ms and locks in the retry; it fails without the
fix.

* Stabilize iOS CI animation and persistence tests (#511)

Synchronize iOS tests with display updates and persistence completion, add deterministic DocSaver scheduling coverage, and conditionally run iOS CI for relevant pull request changes.

* Show the text cursor over selectable chat text (#529)

* Show the text cursor over selectable chat text

Every selectable region (markdown paragraphs and their table/list/quote
kin, code lines, user bubbles) builds on one wrapper that was already
shared: relative + the selection underlay + the text. selectable_
text_wrap() centralizes that wrapper and adds
.cursor(CursorStyle::IBeam), so hovering selectable text reads as text;
the composer was previously the only I-beam in the app.

Links and code action buttons already paint their own cursor_pointer()
hitboxes above this wrapper, and GPUI resolves the topmost hitbox under
the mouse, so hover targets keep the hand cursor.

selectable_text_wrap_is_ibeam_cursor locks the cursor style.

* Keep arrow cursor over code scrollbars

---------

Co-authored-by: Wing <44917547+wingleeio@users.noreply.github.com>

* Fix Windows terminals starting in C:\Windows instead of the project checkout (#528)

* Strip verbatim path prefixes from ConPTY current directories

RunProjectAction canonicalizes the checkout host-side, and
std::fs::canonicalize returns \?\-prefixed verbatim paths on Windows.
CreateProcessW current directories do not accept them: cmd.exe treats
the prefix as UNC and silently falls back to the Windows directory, so
project-action terminals start in C:\Windows instead of the checkout.

plain_current_dir strips \?\ (and rewrites \?\UNC\server\share to
\server\share) before the cwd reaches the spawn.
plain_current_dir_strips_verbatim_prefixes covers the transform.

* Harden Windows terminal cwd normalization

---------

Co-authored-by: Wing <44917547+wingleeio@users.noreply.github.com>

* Restore tab drag-reorder on Windows (#536)

* Restore surface-tab drag reordering on Windows and fix chip drops

Tab drag-reorder on the right-panel surface strip was dead on Windows
and drop-broken on every platform.

The chip's on_drag was gated behind click_activation_drag_enabled()
(false on Windows since the Windows support line) because GPUI's 2px
drag-promotion threshold turns ordinary Windows click jitter into
accidental drags. The gate is deleted: drags attach on all platforms.
This depends on zeronsh/zui#13, which raises the Windows threshold to
the system drag rectangle (SM_CXDRAG, 4px) and must land first, with a
zui pin bump. Merging this before that would bring the accidental drags
back. The updated jitter test (3px sub-threshold jitter stays a click)
fails against the current 2px pin on purpose; it is the guard for that
merge order. Removing the gate also un-gates file-tree row, search
result, and terminal tab drags on Windows.

The strip's on_drop could never fire over a chip: the chip's
block_mouse_except_scroll() carve-out (titlebar/scroll) cuts the strip
out of gpui's hover stack, so MouseUp hit-testing never reached the
strip's drop listener while the pointer was over a tab. Reordering only
worked in the 4px gaps between chips, on every platform. The chip now
receives the drop itself; bubble dispatch reaches the chip before the
strip, and the handler consumes the drag, so the two never
double-apply.

Tests: surface_tab_drag_reorders_the_strip locks the end-to-end reorder
(written red-first on Windows: "surface tab drag never started"); the
Windows jitter test now pins sub-threshold (3px) jitter to still click
without dragging; the platform-policy assertion expects the drag to
start everywhere.

* Pin org-owned ZUI drag threshold dependencies

---------

Co-authored-by: Wing <44917547+wingleeio@users.noreply.github.com>

* Pass window to add_diff_surface from the Diff workspace command

main added WorkspaceCommand::Diff after this branch was cut; the new
add_diff_surface signature needs the window for its subscription.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Laurent <stlaurentcodes@gmail.com>
Co-authored-by: Wing <44917547+wingleeio@users.noreply.github.com>
Co-authored-by: wing-anara <wing@anara.com>
Co-authored-by: Gaël Cado <130941423+gaelcado@users.noreply.github.com>
Co-authored-by: grahamwinter <wwinterr@pm.me>
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Wing <contact@winglee.io>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: wing-anara <wingleeanara@gmail.com>
Co-authored-by: LoikStyle <131105263+LoikStyle@users.noreply.github.com>
Co-authored-by: gaelcado <cado.gael@gmail.com>
Co-authored-by: dcdyouget <57359111+dcdyouget@users.noreply.github.com>
Co-authored-by: Vu Nguyen <hggaming91@gmail.com>
@gaelcado
gaelcado deleted the fix/sidebar-text-fade branch October 1, 2026 11:06
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.

3 participants