Commit Graph
8285 Commits
Author SHA1 Message Date
Merge Sim edd2889846 fix(watchers): own shallow binding teardown completion 2026-09-07 23:02:47 -07:00
Jinjing 36d209f515 Verify failure causality in PR checks fix prompt before making changes (#19435)
* Update PR checks fix prompt to verify failure causality before fixing

Revise the prompt to classify failures as caused by this branch, not caused,
or uncertain before making changes. Only proceed autonomously for confirmed
failures; ask the user for guidance on uncertain or unrelated issues to avoid
fixing failures that weren't caused by the branch.

* Update PR checks fix prompt to verify failure causality before fixing

- Emphasize investigation phase by reframing prompt: "Investigate" rather than "Fix"
- Extend untrusted-data warning to all investigation sources (repository files, commit messages, diffs, CI output)
- Add test verifying injection safety: malicious input confined to JSON payloads, never as prompt instructions

* Refactor buildFixChecksPrompt test to focus on field mapping

The wrapper's only responsibility is renaming mobile PR fields onto the
shared prompt builder. Remove assertions about prompt wording, which are
already covered by the builder's own test suite. Simplify the test to
verify the field mapping contract and nothing else.
2026-09-07 22:47:26 -07:00
OrcaWinandm4air 96c6aa2ae3 perf: parse external automation dates once per run (#19474)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:38:40 -07:00
OrcaWinandm4air d3d939b7a0 perf: precompute Jira priority and timestamp sorting keys (#19472)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:38:34 -07:00
OrcaWinandm4air b52d777c95 perf: index prior memberships during project identity succession (#19463)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:38:01 -07:00
OrcaWinandm4air 894fbc8698 perf: normalize only retained browser history candidates (#19460)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:37:55 -07:00
OrcaWinandm4air 81bd912928 perf: reuse normalized path matchers for batch deletion (#19458)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:37:40 -07:00
OrcaWinandm4air 83167f08ff perf: index VM feature restoration and precompute sorting identities (#19457)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:37:31 -07:00
Jinjing 3b00cfcb2d fix(activity): keep badge in step with monitoring turns; drop dead cache branch (#19535)
Monitoring turns emit no working event (4b2e3dded0), so the titlebar
badge must not count them either, or it lights with no unread row to
clear. The build cache's cached-events ternary could never take its
cached path because the early return above already covers it.
2026-09-07 22:28:23 -07:00
OrcaWinandm4air 990674f7e3 perf: sum omitted workspace sizes without intermediate objects (#19491)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:21:52 -07:00
OrcaWinandm4air 5aaf146795 perf: cache matched and unmatched Claude usage cwd attribution (#19489)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:21:46 -07:00
OrcaWinandm4air 9039cd522e perf: index forgotten Codex turns for bounded ordinal retention (#19488)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:21:39 -07:00
OrcaWinandm4air d0969a4917 perf: parse Git history headers without splitting commit bodies (#19486)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:21:34 -07:00
OrcaWinandm4air 7dd6373e2c perf: skip sorting when all final automation runs fit (#19485)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:21:28 -07:00
OrcaWinandm4air 5d0a45bb92 perf: use counted membership for worker transcript roster twins (#19484)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:21:20 -07:00
OrcaWinandm4air d160c78921 perf: clone only changed work-item pages (#19478)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:21:14 -07:00
OrcaWinandm4air 505af34bb6 perf: stop clone URL discovery at the first usable source (#19477)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:21:08 -07:00
OrcaWinandm4air fb9d08f5f9 perf: index project table option and iteration order (#19476)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:20:57 -07:00
Jinjing 31b84cc71f Fix native PTY I/O failures disabling session termination (#19523)
* Fix native PTY I/O failures disabling session termination

I/O failures on write or resize were incorrectly treated as exit evidence,
which disabled further termination attempts and producer flow control.
Separate ioFailed state from dead state; I/O errors suppress operations
but keep kill, forceKill, and signal available. Publish physical exit
before notifying listeners to prevent reentrant cleanup attempts from
accessing the retired native process.

* Fix PTY I/O cleanup tests and config syntax error

- Fixed missing closing brace and comma in reliability-gates.jsonc
- Added clear() operation to PTY mock fixture and test coverage
- Enhanced assertions to verify operation suppression during I/O failures
- Improved kill operation error handling with better promise-chain assertions
- Updated test result summaries in reliability gate documentation
2026-09-07 22:20:35 -07:00
f0bfc945b4 fix: avoid duplicate repository groups during catalog refresh (#19170)
* fix: keep grouped repositories visible after creation race

* test: strengthen project group creation race verification

---------

Co-authored-by: Kien Le <122910950+kien-ship-it@users.noreply.github.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-09-07 22:19:52 -07:00
OrcaWinandm4air 253fa43256 perf: index editor ownership and restored workspace projections (#19444)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:10:00 -07:00
OrcaWinandm4air 919087897e perf: stop filesystem authorization at the first matching root (#19438)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:09:56 -07:00
OrcaWinandm4air 32510c9041 perf: skip Git-status indexing without eligible editors (#19437)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 22:09:52 -07:00
OrcaWinandm4air d3baad2527 perf: index selected team IDs and choose primary team in one pass (#19504)
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
2026-09-07 21:59:00 -07:00
Jinjing ba5f708290 Rank activity status groups by attention level (#19329)
* refactor(activity): rank status groups by attention level

Establishes consistent group ordering by introducing an attention-based ranking system, ensuring status groups maintain a fixed order regardless of thread recency. Consolidates thread status classification logic into `activityThreadStatusId` and simplifies group key naming.

* refactor(activity): emit working state for live agent turns

Activity events now emit working state for current turns,
enabling attention ranking above historical states.

* fix(activity): preserve working turns and count as unread

- Remove working-state events from cap logic so live turns stay visible
- Count fresh working/monitoring as unread in Activity badge
- Extract state-checking to activity-event-state module
- Use agentStatusEpoch for freshness-based invalidation

* fix(activity): subscribe only to epoch for unread count, not status map

The unread receipt is keyed on turn boundaries (stateStartedAt), not
heartbeats (updatedAt). Only the epoch matters; read the status map
directly via getState() to avoid wasteful re-renders on same-turn
heartbeats.

* fix(activity): prevent monitoring turns from emitting working events

Monitoring turns should surface only via the 'monitoring' snapshot in
the live state, not as separate working events that would contradict
the snapshot signal.
2026-09-07 21:50:14 -07:00
Jinjing 1a8640adb6 Stabilize scrollbar gutter to prevent message list layout shift (#19332)
* Stabilize scrollbar gutter to prevent message list layout shift

- Add `scrollbar-gutter:stable` to prevent reflow when scrollbar appears
- Adjust scroll container padding to properly accommodate the scrollbar
- Add 5px horizontal inset to content for alignment with composer field

* Simplify message list padding and update scrollbar-gutter
2026-09-07 20:24:59 -07:00
Jinjing 217125338e Log error details on session kill failure (#19381)
When a session kill operation fails, capture the error name and message
in the log to aid debugging and performance issue investigation.
2026-09-07 20:20:00 -07:00
Neil 7adb5b3dc4 fix(sidebar): label pinned rows with their host on a multi-host sidebar (#19351)
emitPinnedGroup was the one section emitter that appended worktree rows
without hostContextLabelByWorktreeIdentity, and the mixed-host map it
would have received was computed over naturalWorktrees, which under the
default pinned policy has the pinned worktrees filtered out. Under that
policy a pinned worktree renders only in the Pinned section, so a pinned
remote workspace had no host badge anywhere.

Compute the mixed-host map over the full worktree set and thread it into
the Pinned emitter. Single-host sidebars still draw no badge.

Fixes #18472
2026-09-07 19:54:30 -07:00
Neil 1e693edee4 fix(clipboard): route runtime-owned SSH image paste through the runtime (#17679) (#19352) 2026-09-07 19:54:16 -07:00
Neil fc78a7d9ca fix(runtime): stop a first status publication retiring in-flight worktree scans (#19357)
A paired runtime host's first status publication counted as a connection
change, advancing the connection generation. Worktree scans already in
flight against that same connection were then discarded, so the sidebar
showed a strict subset of the host's worktrees until an unrelated refresh.

Two independent defects, both fixed:

- `connectionChanged` conflated "no entry yet" with "recorded unreachable".
  Only the latter is a reconnect. The provider-session bump keeps the
  broader predicate, since a first publication is a real session start for
  integration-readiness caches.
- A stale-generation result was thrown away with no retry, so even a
  genuine mid-flight reconnect silently dropped completed work. The scan is
  now re-read once against the new generation.
2026-09-07 19:54:01 -07:00
Jinjing 66420537b7 fix e2e create menu races (#19448) 2026-09-07 19:45:54 -07:00
gatsby74andNeil a278d84a4e fix(pi): show input modals as waiting instead of working (#18836)
* fix(pi): show input modals as waiting instead of working

* test(pi): verify real input dialogs through Electron CDP

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-09-07 19:35:19 -07:00
aeddfa463d perf(renderer): avoid per-second spinner animation events (#19407)
* perf(renderer): avoid per-second spinner animation events

* fix(bench): ensure the Electron runtime before bench:spinners

The script launches Electron via Playwright but skipped ensure:electron-runtime,
which every other Electron-launching bench script runs first.

* docs(renderer): scope spinner pixel-tolerance claim to paused-animation checks

---------

Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
2026-09-07 19:29:53 -07:00
Neil da836faeef fix: preserve terminal retirement proof across renderer publications (#19002)
* fix: preserve terminal retirement proof across renderer publications

* refactor: share the live-surface filter between retirement proof preservation and projection

The publication projection already dropped proofs whose surface is live;
reuse that as one helper instead of a second inline scan.

* fix: emit stored retirement proofs from host-authored snapshot writes

Three callers built a snapshot, stored it, then emitted the pre-store object. Storing grafts on the preserved proofs, so those frames carried the stored snapshotVersion without the proofs; subscribers dedupe on version and never saw them.

* fix: send terminal retirement proofs once per stream and fence them by occupant

Proofs are pinned per worktree for the host's lifetime, so every snapshot publication — including a 50ms title tick — re-shipped up to 64 proofs (~17 KB on realistic ids) to every paired client.

Negotiate session-tabs.retirement-proof-delta.v1: the host projects each session-tabs stream to send a proof only the first time that stream carries it, and a capable renderer keeps the union in a ledger keyed by (environment, worktree) with the same 64-entry bound and the same live-surface drop rule as the host, reset on removed frames and on a new connection generation. Legacy clients keep receiving the full list; CLI and mobile do not advertise the capability.

Also inherit worktreeInstanceId onto identity-less host writes so a host write between two renderer occupants can no longer launder one occupant's proofs into the next.

* fix: keep an empty proof delta distinguishable from a proof-less host

A negotiated stream now sends retiredTerminalSurfaces: [] when nothing is new instead of omitting the field. Absence is the host's "I hold no proofs" signal — which is also what a recreated worktree's fresh host entry publishes — so the client ledger forgets on absence and a successor occupant never inherits its predecessor's proofs, even when the removed frame was missed.

* test: pin ledger visibility against a legacy full-list host

An old host sends the full proof list whenever it holds any and omits the field when it holds none. Prove the new client ledger shows exactly what a legacy client would see across that sequence, so forgetting on absence is verified not to regress the mixed-version case.
2026-09-07 19:28:17 -07:00
Jinjing c056c6f9ac Unify sidebar create actions into single dropdown menu (#19375)
* Unify sidebar create actions into a single dropdown menu

- Combine "New workspace" and "Add project" under a unified "Create" button
- Remove layout logic that split these actions based on sidebar width
- Normalize "Add Project" to "Add project" (lowercase) throughout the UI

* Use null instead of 'Unassigned' for unassigned shortcut labels

Add formatOptionalPrimaryShortcutLabel that returns null when a
shortcut is unassigned, enabling simpler conditional rendering in
dropdown menus. Remove associated translation strings.
2026-09-07 19:24:34 -07:00
Neil 98b0c329ff fix: preserve user input during terminal scrollback replay (#19075)
* fix: preserve user input while terminal scrollback replays

* test: model multiple xterm user-input subscribers

* fix: keep mouse reports suppressed during replay and bind forwarders once

Real keystrokes now survive the replay guard, but xterm flags pointer
reports as user input too, and replayed bytes can leave mouse tracking
armed until the guarded mode reset lands. Keep those suppressed so a
click on restoring scrollback cannot print SGR fragments on the prompt.
Hoist the two provenance-bound forwarders out of the per-keystroke path.

* fix: keep wheel cursor keys off a replayed alt-screen frame

xterm turns a wheel notch into cursor up/down when the active buffer has
no scrollback, and flags it as user input. During a dead-TUI restore that
frame is replayed on the alt buffer and only leaves it when the guarded
?1049l lands, so forwarding those arrows would recall shell history at
the fresh prompt. Suppress them on the alt buffer only; the same bytes on
the normal buffer can only be a keyboard arrow and still survive replay.
Group the pointer-derived predicates in terminal-pointer-input-sequences.
2026-09-07 19:15:08 -07:00
Brennan BensonandMerge Sim c1e15c4008 feat(native-chat): read a tool batch as a group (#19372)
* feat(native-chat): read a tool batch as a group

A run of several tool calls collapsed to one joined string: names and
arguments run together, separated by a middle dot that also occurs inside
`browser.open` and `tools/read`, with the overflow cut mid-token. Opened,
the member rows sat flush with the header and with the message content
around them, so the batch had no visible end.

Two presentation changes, no new derivation:

- Each member gets its own bounded pill in the collapsed header, carrying
  its own category glyph, so the boundary between calls is a shape rather
  than a character. Pills wrap instead of truncating, and members past the
  summary cap are counted in `+N more` rather than dropped silently.
- Opened members are indented under the header, which is what marks where
  the run ends.

`toolRunSummaryMembers` keeps the run's leading calls apart instead of
pre-joining them; `summarizeToolRun` now derives its string from it, so
mobile's header is byte-identical and the two cannot disagree about which
calls speak for a run.

Two existing behaviours are pinned by test rather than changed, both being
naming decisions rather than layout ones: the header still prints the raw
`mcp__linear__list_issues` while the row beneath prints the split name, and
a call carrying only a `url` still falls through to a JSON preview clipped
at 28 characters.

* fix(native-chat): bundle hidden tool count copy

* fix(native-chat): drop the filled pill for a glyph-led member list

Rendered in the app, the filled chips were wrong twice over. `bg-accent` is
reserved for hover/active row backgrounds, and the only full-strength use of
it in native chat is on payload and diff surfaces — so each member read as a
shrunken content block, and a run became the loudest thing in the transcript.
Worse, `flex-wrap` degenerated: at a 297px pane each member is 274-288px, so
every one took its own line, the header grew 24px to 72px, and the `5x` count
centred against the block landed beside the second member as though it counted
that call alone.

The glyph already marks where a member starts, so the fill was carrying no
information the icon wasn't. Members are now inline, glyph-led, and separated
by spacing; the list stays one line and truncates as a whole, as it did before
this branch. `+N more` moves outside the truncating span so the count of what
is not shown survives a pane too narrow to print the list.

Members carry `data-tool-run-member` rather than being found by their fill.

* fix(native-chat): let the run summary size to its content

`flex-1` on the truncating member list made it claim the header's slack, so
`+N more` was pushed to the far right edge with a gap between it and the last
member it counts. Without it the span still shrinks and truncates — `min-w-0`
plus the default shrink is what drives the ellipsis, which is how the header
worked before this branch — and the count now sits directly after the list at
every width.

* fix(native-chat): separate run-header members with real whitespace

An `ml-3` margin marks the boundary on screen but is invisible to a copied
selection and to the button's accessible name, so the header read
`ls -latools/read`. Adds a space text node between members and trims the
margin to pay for its width. `+N more` also picks up the hover transition
every other header segment already had.

---------

Co-authored-by: Merge Sim <sim@local>
2026-09-07 18:24:30 -07:00
BingZandNeil 5bd0247aaa fix(xterm): remove scrollback decorations by identity (#13178)
* fix(xterm): fire Marker dispose before clearing line (#10879)

Scrollback trim under search highlights was O(k²) because dispose set
marker.line to -1 before onDispose, collapsing SortedList keys. Fire
listeners first so delete still sees the real line, then clear the line.

Fixes #10879

* fix(xterm): remove scrollback decorations by identity

* perf(xterm): avoid index arrays for unique decorations

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-09-07 18:18:04 -07:00
Brennan BensonandMerge Sim 3b8128df04 fix(orchestration): index per-PTY mailbox reservation cleanup (#19390)
Co-authored-by: Merge Sim <sim@local>
2026-09-07 17:42:23 -07:00
Neil 588240043e fix(sidebar): reveal collapsed workspaces without clearing filters (#19398) 2026-09-07 17:14:54 -07:00
Brennan BensonandMerge Sim 9f044031fc fix(native-chat): render compaction notices, plan documents, and images (#19228)
* fix(native-chat): render compaction notices, plan documents, and images

* fix(native-chat): avoid repeating notice text in details

* fix(native-chat): journal canonical and legacy compaction events

* test: add digest to native chat notice payload fixture

* chore(native-chat): drop the planning doc from the PR

---------

Co-authored-by: Merge Sim <sim@local>
2026-09-07 16:21:47 -07:00
Brennan BensonandMerge Sim d0506bf5de feat(native-chat): add execution details and tool row identity (#19226)
* feat(native-chat): annotate tool rows with execution and source details

* fix(native-chat): require explicit MCP identity for tool annotations

* test: add required state to MCP projection fixture

---------

Co-authored-by: Merge Sim <sim@local>
2026-09-07 13:51:47 -07:00
Brennan BensonandMerge Sim 0b3af9ddbc Show native chat message timestamps on hover and keyboard focus (#19218)
Co-authored-by: Merge Sim <sim@local>
2026-09-07 13:46:21 -07:00
Jinwoo Hong bcd4076dd1 fix(relay): never cache a region hint from a one-region catalog (#19349)
* fix(relay): never cache a region hint from a one-region catalog

The director lists only regions with a serving cell, so a roll wave shortens the
catalog to one entry. The resolver required only every *listed* region to be
measured, so that lone region won against nothing and was cached for 24 h: a US
desktop refreshing while US cells rolled published asia-east2 for a day, the
incident #19233 was written to end. Now fewer listed regions than the fleet serves
withholds the hint (1 h no-hint TTL), the same outcome as an unmeasurable peer.

* test(relay): give the unstable-probe case a two-region catalog so it has one cause
2026-09-07 16:44:33 -04:00
Brennan BensonandMerge Sim 6a47d2831f fix(native-chat): scope composer file drops to the pane that received them (#19328)
* fix(native-chat): scope composer file drops to the pane that received them

A native OS file drop resolving to `target: 'composer'` carried no pane
identity, so the window-wide payload was attached by every mounted composer.
Because inactive chat tabs stay mounted (hidden), one drop populated every
chat pane's attachment cache, and those chips replayed whenever the user
returned to a tab they never dropped into. The workspace-creation composer
and chat composers also leaked into each other, since neither could tell
which surface actually received the drop.

Composer drops now carry a `scopeKey` the way a terminal drop carries its
tab and pane leaf id: the composer publishes its pane key as
`data-composer-scope-key`, the preload harvests it during the composedPath
walk, and each composer attaches only its own. The workspace composer's
last-wins ownership stack now claims unscoped payloads only.

* test(native-chat): supersede the bug-asserting drop repro with the scoping test

The repro that landed on main asserts the pre-fix behavior (a drop reaching
every mounted composer), so it fails once drops are scoped to the pane that
received them. Its scoping cases now live in
native-chat-composer-drop-scope.test.tsx, which keeps its editor-target
control case verbatim and adds coverage for unscoped composers and a scope
key published inside the drop-target marker.

* test(native-chat): cover workspace composer drop isolation

* fix(native-chat): authorize external attachment paths before preview

---------

Co-authored-by: Merge Sim <sim@local>
2026-09-07 13:34:23 -07:00
Brennan BensonandMerge Sim 5cefb440bf fix(native-chat): stop an unanswered host from reading as one that refuses structured chat (#19321)
* fix(native-chat): stop an unanswered host from reading as one that refuses structured chat

`readLocalRuntimeCapabilities()` returned `[]` both before the first status probe
landed and after one failed, so "not asked yet" and "host says no" were the same
value. Every structured-chat launch route consumed it, and an unprobed host was
routed to legacy chat exactly as a refusing one is.

Keep the two apart: the cache holds `null` until a probe succeeds, a failed probe
leaves it `null` rather than emptying it, and the launch route names the case with
its own blocker instead of borrowing `runtime-capability`.

No routing outcome changes — both cases still decline structured chat. The point is
that the reason is now truthful, which is what the routing work needs to build on:
once a launch can target a runtime peer, capabilities come from that host, and an
unanswered remote must not be indistinguishable from one that refuses.

`hostCapabilities` on the launch route stays local-only at every call site; a
per-target resolver replaces it when the route learns to reach a peer.

* test: cover unknown runtime capability lifecycle and launch fallback

---------

Co-authored-by: Merge Sim <sim@local>
2026-09-07 13:25:40 -07:00
Jinjing 1d1b73c408 Defer inactive browser pages across worktree switches (#19326)
* Defer inactive browser tabs while retaining their viewport slots

Restore worktrees and tabs on demand instead of mounting the full tree.
Only render active pages and those required by automation, mobile drivers,
or remote viewers. Inactive panes stay deferred with persistent viewport
slots so their webview guests survive chrome unmounts, reducing memory
overhead when opening workspaces with many tabs.

* Defer browser pages until active and recover if evicted

Pages defer rendering until active, then retain state when inactive.
Add recovery logic to restore guests evicted by workspace memory
pressure when pages are reactivated.

* Stop retaining browser content when worktree is inactive

- Browser panes and pages now unmount when their worktree transitions to inactive, except for pages claimed by automation/mobile/viewer consumers
- Prevents unwanted restoration of all hidden browser tabs when switching between worktrees
- Tests verify proper cleanup at scale and correct page lifecycle across worktree switches

* Preserve document-preview guests when switching browser tab profiles

Document previews use a fixed partition and should not be recreated when
the profile changes. Only URL-based pages need their webviews destroyed
and rebuilt with the new profile. Includes test coverage.

* Create browser pages cold to defer guest initialization

Pages created in the background now start with loading: false, since they
don't own a guest until first shown. Only live guests can report loading
status, so background tabs sit idle until activation triggers navigation.

* Prevent document preview from swallowing pointer events during drag

Move webview registration to attachDocPreviewWebview before append,
ensuring it's enrolled in drag passthrough before becoming hittable.
When a document preview tab remounts mid-drag, the previous hook-based
enrollment landed too late. Also refactor mountEligible into
isBrowserPagePanePaintable for clarity.
2026-09-07 12:20:27 -07:00
Brennan BensonandMerge Sim ce4a3a4186 feat(chat): add structured session rewind backend (#19235)
* feat(chat): add structured session rewind backend

* fix(chat): make interrupted session rewinds recover safely

* fix(native-chat): negotiate rewind runtime capability

* fix(native-chat): consolidate remaining adapter imports

---------

Co-authored-by: Merge Sim <sim@local>
2026-09-07 12:20:24 -07:00
Jinjing 9fed61e5c2 Persist agents sidebar search visibility as pairing-local preference (#19313)
* Persist agents sidebar search field visibility as pairing-local preferen

- Add `agentsShowSearch` to workspace UI state with default on
- Include in pairing-local fields so preference syncs across clients
- Convert search from menu action to checkbox menu item for explicit toggle
- Update activity thread options menu to reflect checkbox state
- Add localization strings across all supported languages
- Update RPC schemas and preference persistence layer
- Includes readiness validation reports confirming feature is clean

* rm review

* fix documentation
2026-09-07 11:27:40 -07:00
Jinwoo Hong 5857357fcf feat(relay): log the region probe and name the assigned cell (#19307)
* feat(relay): log the region probe and name the assigned cell

A desktop silently pinned itself to a far relay region for a day and every
phone connect paid the round trip. Nothing in the desktop logs said which
regions were probed, what they measured, why one was rejected, or which cell
the host landed on, so the only way to diagnose it was a bench harness.

The resolver now emits one line per outcome. A refresh carries every region's
probe origins, the discarded warm-up, the kept samples, the minimum, the
spread, and a verdict, then the chosen region or no-hint with the reason it
withheld one. Cache hits, diagnostic overrides, and a director that cannot
list its regions each get their own line so a quiet run is never ambiguous.
Self-heal logs the cached region, the best measured region, the assigned
cell's round trip, and whether it kept or deleted the cache. Only a refresh
reports a catalog failure; a self-heal never chose a region, so a line saying
it withheld a hint would be a lie.

Relay status now carries the assigned cell so the pairing panel can name it.
The field is optional because an offline host holds no assignment and the web
client answers from a stub that never has one.

Splitting catalog fetching out of the preference module keeps both files
inside the line budget without a lint disable.

* fix(relay): drop the assigned cell from statuses not served on it

The origin pool publishes offline while it still holds the assignment it is
about to rotate, so the panel kept naming a cell nothing was served from. The
same class of bug hid a second instance: the coordinator republishes
registered right after the broker announces its cell, and that republish
carried no cell, blanking the value moments after it was set. The cell would
never have reached the panel in the real flow.

Deriving the cell from the status at each publisher removes both. The rule
lives beside the status type because it defines when the optional field is
populated, and the coordinator reads the owned broker's endpoint rather than
trusting a call site to remember to pass it.

* i18n: add the relay cell label to the English catalog

* test(relay): audit the relocated region catalog fetch call site

* fix(relay): report a self-heal whose catalog request failed instead of staying silent
2026-09-07 13:45:48 -04:00