Skip to content

Merge upstream Zed (764 commits) + fix ACP silent-prompt wedge - #73

Merged
lukemarsden merged 776 commits into
mainfrom
feature/merge-upstream-zed-2026-07-29
Jul 29, 2026
Merged

Merge upstream Zed (764 commits) + fix ACP silent-prompt wedge#73
lukemarsden merged 776 commits into
mainfrom
feature/merge-upstream-zed-2026-07-29

Conversation

@lukemarsden

Copy link
Copy Markdown

Catches the fork up with 764 commits of upstream Zed, and fixes the production wedge that prompted it.

Paired Helix PR (pins ZED_COMMIT): helixml/helix#2896

1. Upstream catch-up (764 commits)

The fork had drifted 41 days behind (last fence e45e42af6e, 2026-06-18). It is now level with upstream/main at b9256fa8f0. Merged in four dated rounds rather than one jump — by far the largest window in this series (previous max 261) — so every conflict is attributable to a bounded upstream window:

Round Range Commits Conflicts
1 e45e42af6e..4b7369481d (→07-03) 254 6
2 4b7369481d..4a3e0af532 (→07-14) 212 3
3 4a3e0af532..d23aaeebea (→07-24) 226 1
4 d23aaeebea..b9256fa8f0 (→HEAD) 72 2

Notable resolutions (full detail in portingguide.md):

  • acp_thread.rs — upstream added an is_same_turn guard emitting StatusChanged. Kept Helix's stopped_emitted_for_task guard (Critical Fixes Default to follow mode when using agent #6/build(deps): bump the npm_and_yarn group across 1 directory with 2 updates #9) and adopted upstream's emit, ordered to match upstream's own sibling arm.
  • agent_servers/acp.rsinto_foreground_future() removed upstream; PR fix(agent_servers): serialize ACP session-creation per connection #50's session-creation slot guard converted to .block_task().
  • config_options.rs — upstream renamed first_config_option_id and added a predicate param; current_model_value() adapted with |_| true to preserve the old first-in-category semantic.
  • open_ai.rs / reqwest_client.rs — two Helix surfaces the porting guide never documented, both of which present as trivial-looking conflicts that are easy to resolve toward upstream and silently drop. Now documented, and covered by the sweep.

New: script/helix-drift-sweep.sh

28 mechanised checks over the rebase checklist. Run before and after every round — a check that passes before a merge and fails after is a dropped fix. This is how the two undocumented surfaces above got caught.

2. Fix: ACP agents that accept a prompt then go silent

Production, 2026-07-29 (spt_01kyq6qd8h4wqq2rfasc4b01e9): claude-agent-acp stayed alive but stopped answering session/prompt. connection.prompt() never resolved, so run_turn emitted no Stopped and no error, and the Helix interaction sat in state=waiting forever with nothing surfaced in either UI. Only a container restart recovered it.

Nothing caught it: the await is unbounded, and PR #63's recovery keys on an ede_diagnostic error string that a silent wedge never produces.

A time-to-FIRST-event watchdog, deliberately not a turn timeout:

  • THREAD_ACTIVITY — a per-thread counter bumped by the persistent subscription on every AcpThreadEvent. Any event is proof of life.
  • Races a freshly dispatched prompt against HELIX_ACP_FIRST_EVENT_TIMEOUT_SECS (default 120s, 0 disables).
  • Disarms permanently on the first event, so arbitrarily long tool calls and slow generations are untouched. A blanket turn timeout would false-positive on exactly those; "zero events since dispatch" cannot.
  • On expiry, drops the send task (same rationale as Critical Fix Upstream merge (Feb 24) + streaming throttle + E2E test infra #8 — never block on a non-responding agent) and raises an error that joins the existing force-close → reload → retry trigger. No new recovery mechanism.
  • A companion per-thread task covers turns started from the Zed UI (which bypass handle_follow_up_message) — that is how the production wedge was actually triggered.

Lives entirely in the Helix-owned crate; upstream diff is zero.

3. Cleanup

crates/agent_ui/src/acp/ (9 files) removed. Orphaned by the 2026-03-22 rename that introduced conversation_view.rs, it has been uncompiled dead code since — no mod acp;, no external references. Not cosmetic: while diagnosing the production wedge, the stale acp/thread_view/active_thread.rs was read as the live interrupt handler when the real one is in conversation_view/.

Validation

  • cargo check --package zed --features external_websocket_sync — clean
  • cargo test -p acp_thread — 127 passed, 1 ignored
  • cargo test -p external_websocket_sync — 55 passed (5 new watchdog tests)
  • Drift sweep — 28/28 after every round
  • Dockerized E2E on the final tree — PASSED both rounds: [zed-agent] 17/17, [claude] 17/17, [store] PASSED (40 interactions / 15 sessions; response-entries isolation clean across 34 interactions in 10 sessions)

Pre-existing breakages repaired (not caused by this merge)

Known gaps (documented, not fixed here)

  • The watchdog covers "zero events after dispatch", not "streamed output then stalled before completing" — that shape disarms it. Observed once in the E2E claude round (correct answer, then no message_completed); did not reproduce. Needs a separate idle-since-last-event budget.
  • e2e-test/run_e2e.sh:204 reports the agent version via npm view @anthropic-ai/claude-agent-acp, but Zed installs @agentclientprotocol/claude-agent-acp — wrong scope, so it always logs unknown, and the one line that would attribute a claude-round failure to an agent-package change is useless. The npm path is also unpinned.

🤖 Generated with Claude Code

reflectronic and others added 30 commits July 17, 2026 19:16
The issue with aws-lc that necessitated this workaround has been fixed
upstream: aws/aws-lc#3197.

Release Notes:

- N/A
On Linux with client-side decorations, opening the workspace sidebar
squared off the window corners on the sidebar's side while the rest of
the window stayed rounded:

Before:
<img width="366" height="239" alt="image"
src="https://github.com/user-attachments/assets/e0ee8d28-6143-42ea-bfd2-10d069df5492"
/>

After:
<img width="426" height="219" alt="image"
src="https://github.com/user-attachments/assets/51d2979d-0103-4742-90bd-a97f5837d99b"
/>

Previously, `client_side_decorations` took a `border_radius_tiling`
override that `MultiWorkspace` used to deliberately square the window
shape on the sidebar's side, since the sidebar painted a square
background that would otherwise poke out past the rounded window border.
The title bar and status bar already skip rounding their corners on the
sidebar side, implying the sidebar is expected to own those window
corners — it just never rounded them.

This PR makes the sidebar round its outer corners the same way the title
bar and status bar do (including overlapping the 1px window border on
untiled edges to avoid a transparent gap in the rounded corners), and
removes the now-unneeded `border_radius_tiling` parameter so the window
border and backdrop round purely based on actual tiling state.

Only applies when the window uses client-side decorations, so macOS and
Windows are unaffected.

Fixes zed-industries#54724 

Release Notes:

- Fixed square window corners on the sidebar side of client-decorated
(Linux) windows when the workspace sidebar is open.

---------

Co-authored-by: Danilo Leal <67129314+danilo-leal@users.noreply.github.com>
# Objective

Fixes zed-industries#60518.

Zed sends an empty `name` for entries in
`initialize.params.workspaceFolders`. Language servers such as
basedpyright use this field to identify workspace service instances,
resulting in an unnamed instance.

## Solution

Derive each workspace folder name from its URI, preferring the decoded
filesystem basename. For basename-less URIs, fall back to a non-empty
path, URI path segment, or the full URI.

Use the same construction for initialization parameters, dynamic
workspace-folder notifications, and `workspace/workspaceFolders`
responses so all LSP messages remain consistent.

## Testing

- `cargo fmt --all -- --check`
- `cargo test -p lsp`
- `cargo check -p project --all-targets --all-features`
- `./script/clippy -p lsp`
- `./script/clippy -p project`

Reproduced with basedpyright 1.39.9 over an LSP stdio session. Before
this change it logged:

```text
Starting service instance ""
```

With a derived workspace folder name it logged:

```text
Starting service instance "zed-60518-project"
```

Tested on macOS.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Fixed language servers receiving empty workspace folder names.
…dustries#61257)

This is a lot of computation work which otherwise hangs the ui thread

Closes FR-122

Release Notes:

- Fixed a cause for ui hangs when interacting with the agent panel
…es#61045)

## Context

Shift-click sometimes extended a selection from an earlier word boundary
after double-clicking a word and moving the cursor with the arrow keys.
Cursor movement changed the selection but left the word or line
selection mode active, so the next Shift-click reused stale selection
bounds. Selection movement now resets the mode to character mode
whenever it changes the selection, while preserving valid empty line
selections that have not been moved.

Closes zed-industries#59913.

Behavior before the fix :

[Screencast from 2026-07-15
13-21-51.webm](https://github.com/user-attachments/assets/c126adfe-f9db-4a04-91c2-6db6e8070182)

Behavior after the fix :

[Screencast from 2026-07-15
13-19-38.webm](https://github.com/user-attachments/assets/19c9f5b6-aaf8-4e8b-b4c5-70327411d1b9)


## How to Review

**`crates/editor/src/selections_collection.rs`**:
`MutableSelectionsCollection::move_with` now resets the selection mode
to character mode when movement changes a selection.

**`crates/editor/src/editor_tests.rs`**: Regression tests cover
Shift-click after collapsing a word selection and confirm that a valid
empty line selection retains line-wise extension behavior.

## Self-Review Checklist

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the UI/UX checklist
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Fixed Shift-click sometimes extending selections from a previous word
or line boundary.
…ruption (zed-industries#60584)

Closes zed-industries#60424

## Problem

With the repro from zed-industries#60424, staging the first deletion hunk marked the
second deletion as staged in the UI even though git still had it
unstaged, and clicking the (incorrectly shown) Unstage button inserted a
duplicate copy of the hunk's contents into the git index on every click.

The root cause is ambiguous hunk placement. The committed text contains
repeated `end\n\n` line runs, so the deletion hunks can "slide": more
than one placement produces a minimal diff. The uncommitted diff (HEAD
vs worktree) anchored the remaining deletion at one row while the
unstaged diff (index vs worktree), recomputed after the partial stage,
anchored the same logical deletion at a different row. Everything that
correlates hunks across those two diffs assumes they agree on positions:

- the secondary-status matching in `hunks_intersecting_range_impl` found
no unstaged hunk at the uncommitted hunk's rows and reported it as
staged (`NoSecondaryHunk`);
- the worktree→index projection in `compute_uncommitted_index_edits`
treated the hunk's position as unchanged text and, on unstage, inserted
the hunk's HEAD content at an index position that already contained it,
duplicating it on every request.

## Fix

Upgrade `imara-diff` from 0.1.8 to 0.2.0 and run
`Diff::postprocess_lines` (imara-diff's port of git's xdiff
slider/indent heuristic) after computing hunks in `buffer_diff`. This
canonicalizes the placement of ambiguous hunks based only on their local
content, so diffs of the same buffer against different base texts anchor
the same logical change at the same rows. A bonus is that Zed's hunk
placement now matches `git diff`'s output for such cases (git has used
the indent heuristic by default since 2.11).

As defense in depth, `compute_uncommitted_index_edits` now drops a
pure-insertion index edit whose content is already present at the target
position, so a stale secondary status can no longer duplicate index
content.

The imara-diff 0.2 API removed the `Sink` trait and the top-level
`diff()` function, so the other call sites (`language/text_diff.rs`,
`zeta_prompt/udiff.rs`, `edit_prediction_metrics/reversal.rs`) are
migrated mechanically to `Diff::compute` + `hunks()` with unchanged
behavior (0.2 also renamed `lines_with_terminator` to `lines` and
changed the default `&str` tokenization to include terminators; the
unified-diff builders keep terminator-less tokens via `str::lines()`).

## Testing

- New regression test `test_staging_hunks_with_ambiguous_placement`
replays the exact repro from zed-industries#60424 (same file contents): stages the
first deletion, asserts the remaining hunks keep their unstaged status
and the index matches exactly, then issues repeated unstage requests for
the unstaged hunk and asserts the index is unchanged. Before the fix
this test showed the second hunk flipping to staged and the index
growing by one copy of the deleted block per unstage request.
- `buffer_diff`, `language`, `zeta_prompt`, `edit_prediction_metrics`,
`multi_buffer`, `git_ui`, `editor`, and the `project` integration suite
pass.
- One test expectation updated: `editor::test_fold_function_bodies`
asserted the old placement of an ambiguous deletion (blank line before
comment); the canonicalized placement (comment before blank line)
matches what `git diff` produces for the same texts.

Release Notes:

- Fixed staging a hunk sometimes marking a different hunk as staged (and
subsequent unstaging corrupting the git index) when the diff contained
repeated lines
([zed-industries#60424](zed-industries#60424)).

---------

Co-authored-by: Cole Miller <cole@zed.dev>
# Objective

- Show accurate diff stats for each staged and unstaged projection of a
partially staged file in the Git panel.
- This was originally considered for
zed-industries#59884, but was scoped out of
that already-large PR and is being submitted separately as discussed
there.

## Solution

- Collect HEAD-to-index and index-to-worktree diff stats alongside the
existing combined HEAD-to-worktree stats.
- Carry the staged and unstaged stats through repository status
snapshots and remote status serialization.
- Use the stat matching the projected Git panel section while preserving
the combined stat for the other grouping modes.
- Update the fake Git repository and add regression coverage with
deliberately different staged and unstaged counts.

## Testing

- `cargo check -p git_ui`
- `cargo check -p collab`
- `cargo test -p git_ui
test_group_by_staging_section_membership_and_order --lib`
- `cargo test -p project --lib --no-run`
- `cargo fmt --all -- --check`
- `git diff --check`

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- Fixed diff stats for partially staged files in the Git panel
…ed-industries#45499)

this pr enables opening a specific line in a diff using zed's cli

Release Notes:
- refactor: add possibility to open specific line in a diff using the
cli

---------

Co-authored-by: Cole Miller <cole@zed.dev>
…industries#51727)

Release Notes:

- Add disable commit actions during commit message generation

---------

Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
…tries#56368)

Release Notes:

- Fixed remote support for adding paths to .gitignore



The problem solved by this PR is: when opening a remote project,
right-clicking a new file in the git panel and clicking "Add to
.gitignore" does not work.

---------

Co-authored-by: Cole Miller <cole@zed.dev>
# Objective

Fixes zed-industries#61244 

In the Agent Panel, after a multi-turn conversation, the action buttons
("Copy this Agent response", "Scroll to User Message", and "Scroll to
top") were only shown after the last assistant response. This was
inconvenient for users who wanted to copy or navigate from earlier
responses.

Additionally, the "Scroll to User Message" button always jumped to the
most recent user message in the entire thread, even when clicked from a
historical assistant response.

This PR addresses both issues by rendering the controls after every
non-blank assistant response, and by making "Scroll to User Message"
jump to the user prompt associated with that specific response.

## Solution

- Refactored `render_thread_controls` in
`crates/agent_ui/src/conversation_view/thread_view.rs` to accept an
explicit `entry_ix`, `copy_response_index`, `is_thread_bottom`, and
`user_message_index`, making it reusable per assistant message.
- Rendered the control bar after each non-blank `AssistantMessage`
entry, not just the last entry.
- Made button IDs unique by using tuple IDs like `("name", entry_ix)`,
matching the existing style in this file and avoiding `format!`
allocations.
- Keyed the copy button ID by the control bar location (`entry_ix`)
while still copying `response_index`'s content, so the bottom fallback
bar doesn't duplicate IDs with the per-response bar.
- Gated the generation/confirmation early return to `is_thread_bottom`,
so historical controls remain accessible while the thread is generating
or waiting for confirmation.
- Gated turn stats and thread feedback buttons to the bottom of the
thread so they only appear on the last response.
- Replaced `scroll_to_most_recent_user_prompt` with a more general
`scroll_to_user_message_index` that takes an optional target user
message index.
- For each per-response button, computed the associated user message
index as the most recent user message before that assistant response.
- For the bottom fallback (when the last entry is not an assistant
message), passed `None` so the button still scrolls to the most recent
user message.
- Updated the tooltip from "Scroll to Most Recent User Message" to
"Scroll to User Message".
- Updated existing tests and added assertions for
`scroll_to_user_message_index(Some(ix), cx)`.

## Testing

- `cargo check -p agent_ui`
- `./script/clippy -p agent_ui`
- `cargo test -p agent_ui --lib` (399 passed)
- Added assertions in `test_scroll_to_most_recent_user_prompt` to verify
`scroll_to_user_message_index(Some(0), cx)` and
`scroll_to_user_message_index(Some(2), cx)` scroll to the correct user
message indices.
- Manual testing recommended: open the Agent Panel, send multiple
messages, and verify that each assistant response has the three buttons
and that "Scroll to User Message" jumps to the corresponding user
prompt.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments (no unsafe blocks)
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

Before: Only the last assistant response in the Agent Panel showed the
"Copy this Agent response", "Scroll to User Message", and "Scroll to
top" buttons. Clicking "Scroll to User Message" always jumped to the
most recent user message.

After: Every non-blank assistant response displays these buttons.
Clicking "Scroll to User Message" on a historical response scrolls to
the user prompt that triggered that specific response.


https://github.com/user-attachments/assets/46e02bcc-8bed-4cf3-a08a-9ef91a206d08

---

Release Notes:

- Added "Copy this Agent response", "Scroll to User Message", and
"Scroll to top" buttons to every agent response in the Agent Panel.
- Fixed "Scroll to User Message" so it jumps to the user prompt
associated with the current response, rather than the most recent user
message.
…ries#61275)

# Objective

Land five small, independent performance fixes found during an audit of
hot paths (anchor resolution, line shaping, worktree scanning, and
sorting in multibuffers).

## Solution

Each fix is its own commit, so **this PR is best reviewed
commit-by-commit** — every commit message contains the full reasoning
for that change:

- `text`: Avoid redundant rope traversal in `Anchor → usize` conversion
— call `offset_for_anchor` directly instead of `summary_for_anchor`,
which recomputed the same byte offset with ~4 extra O(log n) tree walks.
This is the hottest anchor-resolution path.
- `editor`: Avoid double allocation per shaped line —
`line.as_str().into()` instead of `line.clone().into()`, which allocated
twice per visible line, every frame.
- `text`: Use `sort_unstable_by_key` in operation queue insertion —
Lamport timestamps are unique keys and duplicates are deduped right
after, so stability buys nothing.
- `multi_buffer`: Sort with an explicit comparator instead of
`sort_unstable_by_key`, which cloned a `PathKey` (`Arc` refcount bump)
on every comparison.
- `worktree`: Replace O(n²) `Vec::remove` in the deferred-directory pass
with an O(1) `None` assignment — the vec is already
`Vec<Option<ScanJob>>` and is consumed with `.flatten()`.

## Testing

- No behavior changes intended; all changes are mechanical and tests
affected crates pass: `text`, `editor`, `multi_buffer`, `worktree`.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- Improved editor performance through several micro-optimizations in
anchor resolution, line shaping, and worktree scanning.
Restore an optimization that I mistakenly removed in
zed-industries#54728.

Drawing a quad with a border but no fill color will run the quad
fragment shader for every transparent interior pixel, which is
especially costly when the quad is large. Instead, split these quads
into four non-overlapping strips that cover the regions where borders
are painted. The side strips own the straight left and right edges,
while the top and bottom strips own the horizontal edges and the rounded
corners.

Previously, this optimization only applied to borders drawn by the Taffy
layout. I've decided to reinstate the logic directly in `paint_quad` so
that the optimization can be applied more generally... though if this
feels like too much policy, we can move it back.

This reduces the GPU time spent painting a representative Zed scene by
about 20% or so.

Release Notes:

- N/A
…#61283)

Release Notes:

- N/A or Added/Fixed/Improved ...

---------

Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
…ies#61298)

# Objective

When joining lines, Zed checks the next line and strips comment,
documentation-comment, and unordered-list delimiters. The logic trims
whitespace from these delimiters, then checks whether the next line
starts with the trimmed delimiter. If it does, Zed removes the delimiter
before joining the lines.

This works for comment and documentation-comment delimiters, where
trailing whitespace does not affect their meaning. However, it causes
unexpected behavior for unordered-list delimiters, which, as far as I
know, are unique to Markdown.

In Markdown, `* ` is an unordered-list marker, while `*` is also used as
an emphasis delimiter, such as `*italics*` and `**bold**`. The current
logic strips the leading `*` from these emphasis cases, which it should
not.

## Solution

For unordered-list delimiters, Zed should strip the exact delimiter,
such as `* `, rather than the trimmed `*`. It should strip a bare `*`
only when the next line contains only `*`.

## Testing

Tested locally and new GPUI tests were added.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- Fixed markdown emphasis delimiters being removed when joining lines.
…zed-industries#60054)

# Objective

When you make a line selection in a row that is long enough to multiple
lines long while wrapped the selection box will disappear when the
cursor (or just origin of the line selection goes off screen).


## Solution

The when you are in line selection mode the `SelectionsCollection` just
enables `line_mode`, instead of storing the whole ranges of those line
selections, so the Anchor of the selection is a single point.
`disjoint_in_range` filters all the disjoint selections of the
collection to fit inside some range, this is used to render the
selection boxes on screen. `disjoint_in_range` had no special case for
`line_mode` causing it to filter on the point instead of the bounds of
the selection.

My fix is too add a case for `line_mode` that changes the filtering
`Anchor` -> `Point` and then only filters on the row. Then use the
proper bounds of the selection with that:
```rust
        let (start_ix, end_ix) = if self.line_mode {
            let start_row = range.start.to_point(buffer).row;
            let end_row = range.end.to_point(buffer).row;
            let start_ix = self
                .disjoint
                .partition_point(|probe| probe.end.to_point(buffer).row < start_row);
            let end_ix = self
                .disjoint
                .partition_point(|probe| probe.start.to_point(buffer).row <= end_row);
            (start_ix, end_ix)
        } else {
        ...
```

## Testing

Before:


https://github.com/user-attachments/assets/a443de39-53d7-4ee4-b3af-d3be99ca1fcf

After:


https://github.com/user-attachments/assets/18c1c7ef-45cc-4dc8-9a8b-241252c376ab

I also added some tests `disjoint_in_range_line_mode_matches_whole_row`,
being the one that really tests this behavior. the other two are just
for `disjoint_in_range`

I am using macOS 27.0 Beta (26A5368g), but I noticed this bug before
upgrading.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- editor: Fixed bug where selection boxes wouldn't render when the
cursor was offscreen.
# Objective

When using column Git blame with avatars enabled, blame entries whose
author name is the longest in the buffer can exceed the blame border.

For example, line 10 of `crates/vim/src/visual.rs` is displayed as
follows:

<img width="998" height="121" alt="issue"
src="https://github.com/user-attachments/assets/eff3e1ff-bd1c-42af-ae9b-da8efb0a7c22"
/>

The blame contents exceeds the width.

The root cause is in the blame width calculation:

https://github.com/zed-industries/zed/blob/0c51c7fd2481859e9da5c490ef8e41ddbcf1a341/crates/editor/src/editor.rs#L11583-L11598
The calculation accounts for the commit SHA, author name, and timestamp.
Other elements, including spacing, margins, and the avatar, are
represented by the fixed `SPACING_WIDTH` constant.

For typical fonts, `ch_advance` is approximately `0.5rem` to `0.6rem`,
so `SPACING_WIDTH` provides approximately `2rem` to `2.4rem` for
non-text content. However, the avatar itself occupies `1rem`:

https://github.com/zed-industries/zed/blob/0c51c7fd2481859e9da5c490ef8e41ddbcf1a341/crates/ui/src/components/avatar.rs#L81
When avatars are displayed, the entry also contains three `0.5rem` gaps
and also one `0.5rem` right margin:

https://github.com/zed-industries/zed/blob/0c51c7fd2481859e9da5c490ef8e41ddbcf1a341/crates/git_ui/src/blame_ui.rs#L170-L188

This requires approximately `3.0rem`, which can exceed the space
provided by `SPACING_WIDTH`. When an entry contains both the longest
author name in the buffer and a long timestamp, its content can
therefore exceed the blame border.

## Solution

The simplest fix would be to increase `SPACING_WIDTH`, but that would
still rely on an approximate conversion between editor character widths
and UI dimensions.

Instead, this PR adds a method to the blame renderer for calculating the
non-text width of a blame entry. The editor uses this value together
with the measured text width when calculating the final blame width.

## Testing

Tested locally. A before-and-after comparison is included below.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

| Before | After |
| :--: | :--: | 
| <img width="551" height="94" alt="Before"
src="https://github.com/user-attachments/assets/b6741a41-6531-4fae-adaa-f9ae0b298e0f"
/> |<img width="566" height="93" alt="After"
src="https://github.com/user-attachments/assets/e8d75d2a-6b07-43f6-b2a8-bfb76d118611"
/> |

Release Notes:

- Fixed Git blame entries overflowing the gutter when avatars are
displayed.
Found some unnecessary allocations and an `.unwrap()` while working on a
separate issue. The PR makes no behavior changes and should be trivial
to review.

## Testing

All tests pass. These changes are not expected to change any behavior.

None of the changes are interleaving, so it should be easy to review
top-down. Reasoning for each change can be read from individual commit
messages.

Release Notes:

- N/A or Added/Fixed/Improved ...
…ansparent themes (zed-industries#61268)

# Objective

As part of the transparent-window artifact fixes in zed-industries#58981, multibuffer
header backgrounds stopped rendering whenever the window was transparent
or blurred.

This caused a regression for transparent themes, which commonly use an
opaque multibuffer header background to prevent editor text from showing
through sticky headers.


## Solution

Render `editor_subheader_background` when either the window or the
configured background color is opaque.

This restores opaque multibuffer header backgrounds as a mask for the
editor content beneath them, while preserving the zed-industries#58981 behavior for
translucent backgrounds that would otherwise create a darker layered
region.

## Testing

Manually verified locally with a transparent theme that an opaque
multibuffer header background is rendered and prevents editor text from
showing through sticky headers.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

**Nightfox - opaque / blurred**

Before:

<img width="2566" height="1771" alt="图片"
src="https://github.com/user-attachments/assets/55b333bc-b029-4079-9bbc-86462a3f41a7"
/>


After:

<img width="2444" height="1687" alt="图片"
src="https://github.com/user-attachments/assets/217e1ee7-717c-4961-8db0-5eac8104e5bb"
/>

---

Release Notes:

- Fixed editor text showing through multibuffer headers and overlapping
header text in transparent themes.
…ustries#61253)

# Objective

Closes zed-industries#41743

When selecting text on the last line, excluding the trailing newline,
Vim and Helix modes behave differently from native Vim and Helix when
the file has a trailing newline:
1. We cannot use `l` (move right) to include the final `\n` in the
selection, while native Vim and Helix allow this.
2. By default, the rendered cursor should appear on the selected
character. When that character is the final `\n`, however, Zed renders
the cursor on the synthetic empty line after it rather than at the end
of the preceding line. This differs from native Vim and Helix, as well
as from Zed's behavior for newlines elsewhere in the file.
3. When the final `\n` is selected, it affects subsequent selection
motions, as reported in zed-industries#41743.

The cause is several special-case guards for trailing newlines in Visual
and Select modes. These guards exist in the cursor rendering logic:

https://github.com/zed-industries/zed/blob/c9e8e611dbc279afa0914d28c4d37ad07f38c03b/crates/editor/src/element.rs#L201-L213

They also exist in the Visual motion logic for Vim mode and the Select
motion logic for Helix mode (the Helix implementation was adopted
directly from Vim in zed-industries#43234):

https://github.com/zed-industries/zed/blob/c9e8e611dbc279afa0914d28c4d37ad07f38c03b/crates/vim/src/visual.rs#L254-L259

Finally, they exist in the selection extension logic for Vim and Helix
(the Helix logic was also adopted from Vim):

https://github.com/zed-industries/zed/blob/c9e8e611dbc279afa0914d28c4d37ad07f38c03b/crates/vim/src/visual.rs#L273-L284

These guards cause trailing-newline selections to behave inconsistently
with selections containing newlines elsewhere in the file.

## Solution

Remove all the guards mentioned above, including those in cursor
rendering, Visual and Select motions, and selection extension. And due
to the cursor rendering logic is also changed, an exsisting test is
updated.

After removing these guards, I could not reproduce the unexpected
behavior described in the existing comments:

https://github.com/zed-industries/zed/blob/c9e8e611dbc279afa0914d28c4d37ad07f38c03b/crates/vim/src/visual.rs#L247-L253

The only remaining difference is that, when the cursor is on the last
line in Visual mode, pressing `j` moves it to the final `\n` rather than
to the synthetic empty line after it. In comparison, native Vim and
Helix do nothing in this case.

## Testing

- Built and tested locally.
- Added new GPUI tests.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable


Release Notes:

- Improved Vim Visual and Helix Select modes when selections include a
trailing newline.
…roup (zed-industries#61062)

# Objective

Before this PR we would show inside the recent project picker the
projects per group (window) which is great, but when you were trying to
remove a project from the group it would show you a label that includes
the just removed project and also when you clicked on it, it would bring
you back to the 2 project's in the same window in this case.

## Solution

My solution is when we actually remove the project from a group, we also
update the group key that includes the newly updated path list, that
should no longer have the removed project path in it. I also refactored
it a bit so we have one method that does the project removing part so we
don't have to duplicate this logic.

## Testing

You can produce this when you do the following:
1. Open Zed
2. Add 2 projects to your window using the project panel
3. Open the recent project picker
4. See that the `This window` header shows 2 projects
5. Remove one of the projects
6. See that below the `This window` header we would show you a entry
that shows you `projectA, projectB` where **projectb** should be removed
from the group.

I also added a regression test that covers this issue, so we can make
sure the change actually works and does not regress of couse :).

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

**Before** (**Note** before this change we showed the group project
names comma seperated)


https://github.com/user-attachments/assets/750358f4-f347-4f91-86b7-6500b2e09af9

**After** (**Note** after we now updated the groups key so it does not
include the removed project)


https://github.com/user-attachments/assets/f15acea8-d936-4aab-b5c2-324ee49f74a2

---

Release Notes:

- Recent projects: Fixed that it shows you a removed project from a
group
…ries#61161)

# Objective

Fixes zed-industries#59983.

Reducing the Zed window height with the terminal open can clip the
Bottom Dock and terminal content. The dock should shrink to remain
within the workspace instead of extending beyond the window.

## Solution

Restore height clamping for Bottom Dock panels by skipping
`clamp_panel_size` only when a panel actually uses flexible width.
Flexible sizing remains unchanged for the Left and Right Docks, while
Bottom Dock panels once again reduce their stored height to fit the
available workspace.

## Testing

Added a regression test that distinguishes flexible Bottom and Right
Dock behavior. It confirms that the Bottom Dock is clamped while the
flexible-width Right Dock is not. The test failed with the previous
condition and passed with this change.

Manually verified the reported window-resizing scenario locally.


## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

+ Before


https://github.com/user-attachments/assets/c56995a8-47c6-45b6-aeb4-b0b56477c737

+ After


https://github.com/user-attachments/assets/97b5ca6f-cf6f-4dd5-b981-e44bd8139490

---

Release Notes:

- Fixed bottom dock clipping when resizing windows.
# Objective

Fixes zed-industries#59304

Right now inline html tags don't render with any kind of highlighting,
despite the fact that non-inline html tags do get highlighting.

## Solution

Right now zed already has tree-sitter rules that identifies the inline
blocks so we can add a new tree-sitter grammar rule,
```
((html_tag) @injection.content
  (#set! injection.language "html")
  (#set! injection.combined))
```
that passes these blocks to the html language server.

## Testing

I did some manual testing:


https://github.com/user-attachments/assets/92e5b322-bbc1-48c3-a615-0d32acc2e7d6

And also added a test:
test_markdown_inline_html_highlighting


## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- markdown: Fixed inline html block highlighting.
)

# Objective

Make the branch picker easier to scan and ensure branch creation and
remote icons behave consistently across All, Local, and Remote filters.

## Solution

- Group local and remote branches under their own headers in the All
filter.
- Place the create-branch option above branch sections when there is no
exact branch-name match.
- Resolve each remote's hosting provider from its URL and show the
provider icon for branches from that remote.
- Include remote URLs in remote-workspace repository responses so
arbitrary remote names work without hardcoding `origin` or `upstream`.

## Edge Cases Fixed

- An exact branch can exist outside the active Local or Remote filter.
The picker now checks all branches before offering to create a duplicate
branch.
- A non-exact search can return fuzzy branch matches and a create
action. The create action now stays at the top, before the Local and
Remote section headers.
- When a filtered search has no branch matches, the create action is
shown without incorrectly placing it under a Local Branches or Remote
Branches header.
- Repositories can use any remote name, not only `origin` and
`upstream`. Provider icons are resolved independently for every
configured remote.
- Remotes hosted on an unknown or unsupported forge use the generic
server icon instead of implying a desktop or a specific provider.
- Remote-workspace repositories carry the same remote-name-to-URL data
as local repositories, so their branch icons follow the same
provider-resolution path.

## Testing

- `cargo check -p git_ui --no-default-features`
- Branch picker test suite (17 tests)
- `git diff --check`

Tested on macOS.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

<img width="560" height="522" alt="Screenshot 2026-07-17 at 11 19 27 PM"
src="https://github.com/user-attachments/assets/28d57315-b859-4a8d-86ca-53f9fb513bf5"
/>

The updated branch picker groups local and remote branches, keeps the
create-branch action above those sections, and shows forge-specific
icons for remote branches.

---

Release Notes:

- Improved branch picker filtering, grouping, branch creation
suggestions, and remote-provider icons.
…ne (zed-industries#61218)

Closes zed-industries#54951

## Problem

The quick action bar's preview button (markdown, SVG, and CSV behind the
feature flag) resolved everything through `workspace.active_item()` —
the globally *focused* item — instead of the item of the pane the button
sits in. With `A.md` in the left pane and focus in `B.md` in the right
pane:

- Clicking the eye button in **A.md's** toolbar opened a preview of
**B.md**, in the right pane.
- Focusing a non-previewable file (e.g. `B.sh`) in one pane hid the
button in **every** pane's toolbar, making `A.md` unpreviewable by
mouse.

Clicking the button dispatched the `OpenPreview` action, whose
workspace-level handler re-resolved the focused editor — so a click on a
specific pane's toolbar was functionally identical to pressing the
keybinding, discarding the pane the click happened in.

## Fix

Make the flow pane-explicit end to end:

- **Visibility:** each pane's `QuickActionBar` resolves the preview type
from its own `active_item` (set via `set_active_pane_item`) instead of
the workspace's focused item.
- **Click:** no more action dispatch. The handler resolves its pane via
`Workspace::pane_for` and calls new pane-explicit helpers —
`open_preview_in_pane` / `open_preview_to_the_side_of_pane` — extracted
from the action-handler bodies in all three preview crates. Keyboard
actions keep their focus-based semantics and route through the same
helpers with the focused editor and active pane.
- **Alt-click** (open in split) now splits relative to the button's pane
via the new `Workspace::adjacent_pane_of` (the existing `adjacent_pane`
delegates to it).

Notably *not* done: focusing the button's pane and re-dispatching the
action. `workspace.active_pane` only updates when pane focus-in
listeners fire at the end of the next draw, while dispatched actions run
before it — the handler would still read the stale pane.

## Additional changes

- Existing-preview lookup now happens **before** view construction,
instead of building a full preview view (subscriptions, initial parse)
and discarding it when one already exists.
- The `focus` flag now also applies to the activate-existing branch, so
open-to-the-side never steals focus — previously the *first* invocation
left focus in the editor but a *repeat* invocation focused the existing
preview (and cancelled collaborator-following in that pane as a side
effect).
- SVG handlers no longer double-check `is_svg_file`; CSV handlers reuse
`resolve_active_item_as_csv_editor` instead of inlining it;
`is_markdown_file` takes `&App` instead of a needless `&mut Context<V>`.

## Testing

- New regression test
`preview_opens_for_the_given_pane_not_the_focused_editor` reproducing
the issue's setup (two panes, focus in the second, preview invoked for
the first pane's editor), asserting the preview opens in the invoking
pane bound to that pane's editor with the focused pane untouched.
- Markdown/SVG/CSV preview suites and the full `workspace` suite pass;
`./script/clippy` is clean.

Release Notes:

- Fixed the preview button (Markdown/SVG) previewing the focused file
instead of the file in the pane the button belongs to when multiple
panes are open
…1201)

# Objective

Closes zed-industries#4868.

Untitled buffers start as Plain Text and require users to select a
language manually before receiving syntax highlighting. Add lightweight
automatic language detection for code entered or pasted into untitled
buffers.

## Solution

This builds on [Max Stevens's earlier language-detection
work](zed-industries#43057), replacing
Magika with [Betlang](https://github.com/DioxusLabs/betlang).

While researching smaller and faster alternatives to Magika, I came
across Betlang, a recently introduced language detection library
developed by DioxusLabs for dioxus-code. The fact that it comes from
DioxusLabs gave me more confidence in evaluating this relatively new
dependency for Zed. Betlang embeds an approximately 50 KB model, is
MIT-licensed, and depends only on `fearless_simd`, making it well suited
to Zed's cross-platform embedding requirements.

Detection runs on the background executor with bounded input sampling.
It is restricted to untitled buffers, skips content shorter than 20
bytes, and requires at least 50% confidence. These limits have worked
well in local testing. In release builds on Linux with an Intel Core
i5-13600KF, the `betlang::detect` call alone typically completes within
3 ms when processing the maximum sampled input.

## Testing

I added a test for language detection in untitled buffers that covers
both manually entered and pasted content. The test passes successfully.
I also manually tested the feature to verify that the overall experience
works well.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase



https://github.com/user-attachments/assets/96e28ad7-2968-4325-9aff-37fe813a2da7



---

Release Notes:

- Added automatic language detection for untitled buffers.

---------

Co-authored-by: Max Stevens <maxstevens2708@gmail.com>
…ve (zed-industries#60880)

run htop or btm and you can't select terminal text with shift+drag, the
usual escape hatch does nothing.

zed-industries#25143 made shift+click only ever extend a selection, never start one.
so with nothing selected there's no anchor and the drag has nothing to
grab. now it drops an anchor when there's no selection, and still
extends when there is.

added two event-level tests (harness can't sync without a window):
shift+drag under mouse tracking, which fails without the fix, and
shift+click still extending.

Fixes zed-industries#60254.

Release Notes:

- Fixed Shift+click-drag not selecting terminal text while an app has
mouse tracking enabled
… right-click (zed-industries#60892)

# Objective

The contextmenu listener cancelled the browser's native menu
unconditionally, so pages hosting a gpui app lost right-click entirely
wherever the app showed no menu of its own, and apps that do show one
had no native menu to suppress selectively.

## Solution

Record whether the right-button MouseDown dispatch was consumed (a
handler called stop_propagation, e.g. to open a custom menu) and cancel
the native menu only in that case: app menus win where they exist, the
browser menu everywhere else. Apps opening custom context menus should
mark the triggering mousedown consumed to opt in.

## Testing

Tested locally

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

<img width="816" height="288" alt="context menu"
src="https://github.com/user-attachments/assets/c79cd2ef-d465-4431-8461-7a9feb922576"
/>


Release Notes:

- N/A
## Context

Buffer search did not work in file diffs opened from the Git panel
because `SoloDiffView` did not expose its embedded editor as searchable.
Restoring search also revealed that the primary toolbar clipped several
search controls, so the deployed search bar now uses the full-width
secondary row for this view.

Closes zed-industries#60659.

## How to Review

Three files changed. Read in this order:

**`crates/git_ui/src/solo_diff_view.rs`** :
`SoloDiffView::as_searchable` now returns its embedded
`SplittableEditor`, restoring search for the focused diff side while
keeping the editor hidden from global diff-style controls.

**`crates/search/src/buffer_search.rs`** : Buffer search now detects
when its searchable split editor is intentionally hidden by the
containing item. When deployed, this case uses the secondary toolbar row
so Toggle Replace, search options, match navigation, and match counts
remain visible. Other multibuffer layouts keep their existing primary
toolbar location.

**`crates/git_ui/src/git_panel.rs`** : The regression test now opens a
solo diff through the Git panel, confirms the split editor is
searchable, deploys buffer search, verifies the secondary toolbar
location, runs a query, and checks that the focused editor receives a
search highlight.

Manual test after the fix below :

[Screencast from 2026-07-14
00-39-04.webm](https://github.com/user-attachments/assets/022ab106-d35a-4a75-98db-8809b86fa58d)

## Self-Review Checklist

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the UI/UX checklist
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Fixed searching in file diffs opened from the Git panel.

Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com>
… startup (zed-industries#60960)

the startup terminal can take a sec to come up if your shell is slow.
when it's ready it grabs focus, and if you've opened the command palette
by then, that blurs the palette input and closes it. so it just
vanishes.

`add_center_terminal` focused the new terminal unconditionally. now it
skips the focus if a modal is open (`!has_active_modal`). one line at
the definition, covers all the call sites.

kept it terminal-specific like dinocosta framed it. could do a broader
workspace-level "don't steal from a modal" instead if you'd prefer.

two tests: modal stays focused after a background terminal spawns (fails
without the fix), and no-modal still focuses the terminal like before.

Fixes zed-industries#60762.

Release Notes:

- Fixed a background terminal finishing startup closing the command
palette or an open picker
lgeiger and others added 26 commits July 29, 2026 09:25
…#60503)

This builds on zed-industries#59521 and addresses @dinocosta's comment
zed-industries#59521 (review)

Looking at it again, I think
zed-industries@e7ed02c
was too conservative. Re-running the access check on every commit,
stage, or checkout, doesn't really make sense. Access depends on `.git`
ownership/permissions and on the global `safe.directory` config.

File writes in `.git/` can actually never change the access. The only
case where this access can change is an external command that changes
the ownership or permission of the folder. That sounds like a quite rare
edge case and I'm not 100% sure whether all file watchers even currently
correctly trigger events for ownership changes. @dinocosta Let me know
what you think.

Release Notes:

- Improved Git Panel performance by avoiding redundant repository access
checks.

Co-authored-by: dino <dinojoaocosta@gmail.com>
Instead of a dropdown, it is now just a one-click icon.

Self-Review Checklist:

- [X] I've reviewed my own diff for quality, security, and reliability
- [X] Unsafe blocks (if any) have justifying comments
- [X] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [X] Tests cover the new/changed behavior
- [X] Performance impact has been considered and is acceptable

Release Notes:

- Improved theme toggle for the documentation website

---------

Co-authored-by: Gaauwe Rombouts <mail@grombouts.nl>
Use `web_time::Instant` instead of `std::time::Instant` when advancing
scrollbar animations. This uses the web platform's compatible clock in
WASM builds.

Release Notes:
- N/A
# Objective

Fixes zed-industries#61687

Prior to zed-industries#60772, an `abs_path` outside the `repo_root` would cause a
panic. That PR changed it to return the `abs_path` itself, preventing
the panic, but allowing all parents of `repo_root` to be subject to the
global ignore.

This is not what git itself does.

## Solution

- This change returns `false` when the `abs_path` is outside the
`root_repo`, preventing the panic but also not returning the `abs_path`

## Testing

- One in-memory test
- Manual test by building Zed and confirming the project pane changes
(pictured below)

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

### Before, with the bug

<img width="1430" height="814" alt="Screenshot 2026-07-26 at 11 44
11 AM"
src="https://github.com/user-attachments/assets/66e3bb95-4f45-4fd9-a1e4-e7f253f092eb"
/>

### After the fix

<img width="1568" height="1042" alt="Screenshot 2026-07-26 at 12 34
58 PM"
src="https://github.com/user-attachments/assets/588eb01d-830a-4c22-93c0-667742de90b6"
/>

Release Notes:

- Fixed the project panel's global gitignore incorrectly matching parent
directories of a repository

---------

Co-authored-by: dino <dinojoaocosta@gmail.com>
…zed-industries#61837)

# Objective

- GPUI provides `grid_cols_min_content()` and `grid_cols_max_content()`,
but the `grid_rows_*_content()` methods are missing.

## Solution

- This PR adds the `grid_rows_min_content()` and
`grid_rows_max_content()` methods, and renames the enum
`TemplateColumnMinSize` to `GridTemplateMinSize`.

## Testing

- I have tested locally.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable


Release Notes:

- N/A
…1674)

# Objective

When `git clone` fails, the error message produced by git is collected,
propagated, and finally displayed to the user in a pop-up. However, the
pop-up always contains an extra blank line.

The root cause is that Zed builds the error message using simple string
concatenation:

https://github.com/zed-industries/zed/blob/82aef44308540b576e4e51fb379efa71614e5c91/crates/fs/src/fs.rs#L1253-L1258
and the error message from `git clone` contains a trailing newline,
which results in the blank line in Zed's error pop-up.

## Solution

Trim the trailing whitespace from the error message produced by `git
clone`.

## Testing

Built and tested locally. The before/after comparison is shown below.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

## Show Case

| Before | After |
| :--: | :--: |
| <img width="846" height="937" alt="Before"
src="https://github.com/user-attachments/assets/26b918b9-57dc-46e8-880a-525dd4ae257d"
/> | <img width="840" height="952" alt="After"
src="https://github.com/user-attachments/assets/fb6380e3-afad-4a5a-98b1-05e059fd16f5"
/> |

Release Notes:

- Fixed extra blank line appearing in git clone error messages
# Objective

A failed restore, for example, a collision at the original path, used to
remove the `TrashedEntry` from the registry before attempting the
operation, so any later attempt with the same `TrashId` would report an
`AlreadyRestored` error, even though the item still sat in the system
trash.

## Solution

Update both `RealFs::restore` and `FakeFs::restore` to remove the entry
only after the restore succeeds. There's also a small unrelated change
in `ProjectPanel::drag_onto` to log, rather than silently discard, a
failed undo-history record in the project panel, matching existing call
sites.

## Testing

Introduced a new test for these changes
– `restore_can_be_retried_after_collision` .

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- N/A
Fixes zed-industries#60270.

## Summary

- Accept MCP HTTP SSE `data:` fields when the optional space after the
colon is omitted.
- Add a regression test covering `data:{...}` streamable HTTP responses.

## Tests

- `cargo fmt --check`
- `cargo test -p context_server
test_sse_data_field_without_space_after_colon -- --nocapture`
- `cargo test -p context_server -- --nocapture`

Release Notes:

- Fixed MCP HTTP context servers timing out when SSE data fields omit
the optional space after the colon.

---------

Co-authored-by: dino <dinojoaocosta@gmail.com>
…ated (zed-industries#61852)

Closes zed-industries#39286

## Problem

Switching the keyboard layout on Wayland (e.g. GNOME's Super+Space)
makes the compositor briefly grab the keyboard, which deactivates the
Zed window. GPUI reports window deactivation as a blur of the focused
element (`WindowFocusEvent` is emitted with an empty
`current_focus_path`), so controls that dismiss or cancel on blur
treated it as the user abandoning them. The same happens when switching
to another app window. As discussed in zed-industries#39286 with @MrSubidubi, the
desired behavior is to keep these controls open and focused across
window deactivation.

## Fix

Guard the blur-driven cancel/dismiss handlers with
`window.is_window_active()`, following the pattern established for
pickers in zed-industries#41320:

- Project panel: in-progress rename / new file / new directory inputs
are no longer cancelled when the window is deactivated
- Collab panel: in-progress channel rename is no longer cancelled
- Go to Line: the dialog is no longer dismissed

In-window focus changes (clicking elsewhere, Escape) keep the existing
commit/cancel semantics. The terminal tab rename needed no change: it
re-checks `FocusHandle::is_focused`, which reads `window.focus` and that
survives deactivation. Command palette, file finder, and outline were
already fixed by zed-industries#41320.

Added a regression test (`test_rename_survives_window_deactivation`)
that starts a rename, deactivates the window via the test platform, and
asserts the edit state survives.

Two milder siblings were left unchanged to keep this PR focused,
flagging them for a maintainer decision: the notebook markdown cell
exits edit mode on blur (`crates/repl/src/notebook/cell.rs`), and the
diagnostics view prunes diagnosticless buffers on blur
(`crates/diagnostics/src/diagnostics.rs`).

Longer term it may be worth carrying the blur cause in the event itself
(e.g. a `FocusMoved` vs `WindowDeactivated` reason on `FocusOutEvent`
and `EditorEvent::Blurred`), so each handler has to state which causes
it handles instead of relying on an opt-in guard; happy to file a
separate issue for that.

## Before



https://github.com/user-attachments/assets/9eec1bb5-1881-4b3a-80ef-a287e23219ca

## After



https://github.com/user-attachments/assets/49b8775c-175a-4882-835d-871432c0b315

## Suggested .rules additions

> Handlers that cancel or dismiss UI on blur (`EditorEvent::Blurred`,
`on_blur`, `on_focus_out`) must check `window.is_window_active()` first:
GPUI reports window deactivation (app switch, layout switcher grabbing
the keyboard) as a blur of the focused element, and dismissing there
loses user input.

Release Notes:

- Fixed in-progress file renames, channel renames, and the Go to Line
dialog being cancelled when the window is deactivated, e.g. by a
keyboard layout switch on Wayland or by switching to another application
([zed-industries#39286](zed-industries#39286)).

---------

Co-authored-by: MrSubidubi <finn@zed.dev>
Fixes the bug that made us remove the sandbox.

The bug in question was very dumb:
- there is sophisticated machinery for detecting whether a user-granted
writable path is swapped out for a symlink in the timing gap between
approval and sandbox creation
- there was no equivalent machinery to do the same for the (much larger)
gap between a user *persisting an approval* (either for the current
thread or permanently via settings)
- The fix is essentially to store canonical (i.e. absolute and
symlink-free at all depths) paths as the source of truth, but retain the
raw path for display purposes
- On WSL, there is extra care needed becasue of the bidirectional
mounting (i.e. `/mnt/c/...` and `\\wsl.localhost\Ubuntu\...`). In
particular, `/mnt/c/...` paths, since their inodes do not necessarily
pin NTFS file references, weaken the sandbox guarantees, and so we need
some extra UI to call this out and docs etc...

This also does not remove the feature flag, but just toggles it to
"enabled_for_all"

---

Release Notes:

- N/A or Added/Fixed/Improved ...

---------

Co-authored-by: Richard Feldman <oss@rtfeldman.com>
Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
…61270)

# Objective

- Fix multi-stroke keybindings such as `ctrl-x k` being intercepted by
the macOS Japanese IME before GPUI can complete the binding.
- Preserve IME-first handling for ordinary Japanese text input and
active marked-text composition.
- Fixes zed-industries#56043.

## Solution

- Stop preferring IME-first printable input while a valid multi-stroke
keybinding is pending. This allows the next printable keystroke to reach
GPUI and complete the binding.
- Consider pending input active only when it belongs to the window's
current focus. This prevents stale pending state after a focus change or
blur from bypassing normal IME handling.
- Preserve the existing macOS active-composition path, so marked text,
candidate selection, and composition commands continue to reach
`NSTextInputContext` first.

## Testing

Manually tested on macOS using Apple’s built-in Japanese–Romaji/Hiragana
input source with a `ctrl-x k` keybinding. Also added regression test
for pending keybinding routing.


## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- Fixed multi-stroke keybindings not completing when using a Japanese
IME on macOS.

---------

Co-authored-by: Tom Houlé <tom@tomhoule.com>
…-industries#61789)

### Objective

PR zed-industries#58902 made native macOS window chrome follow the selected theme, but
AppKit can synchronously invoke `viewDidChangeEffectiveAppearance` while
the settings observer holds an `App` borrow. `handle.update` then fails
with `RefCell already borrowed`, leaving `Window::appearance()` and its
observers stale.

### Steps to reproduce

1. Set Zed's theme mode to Dark.
2. Set macOS Appearance to Light.
3. Change Zed's theme mode to System.
4. Notice that the window chrome switches to light, but Zed's UI remains
dark.


https://github.com/user-attachments/assets/f91962cc-76ba-4d8e-b587-2a2343f365ba

### Expectation

Zed should switch to its configured light theme when returning to System
mode.

### Solution

Defer `Window::appearance_changed` to the foreground executor so the
current `App` borrow finishes before refreshing the cached appearance
and notifying observers.

### Testing

- Added a regression test.

### Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- N/A
Release Notes:

- N/A

Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
# Objective

- Fixes zed-industries#59409. Closes FR-143. Zed's managed npm directory reaches
10–17GB on machines that use
  external agents, and is never pruned.
- Two independent causes: registry agents are launched with `npm exec`,
which keys its
install directory on the requested version, so every agent release
leaves a full
~250MB copy behind; and npm never evicts anything from its download
cache.

## Solution

- Install registry agents into a directory we reuse, so npm replaces the
previous
version in place instead of accumulating one copy per release. As a side
effect,
updates now download only the changed dependencies rather than the whole
tree.
- Empty the download cache on startup. Nothing in it needs to survive a
restart, since
packages are installed elsewhere. It has to go wholesale: deleting
individual
downloads leaves npm's index pointing at missing files, and npm then
fails with
  `ENOENT` rather than fetching them again.
- The first launch after this does one full agent install as it moves
into its new
  home, and reclaims whatever the old directories were holding.

## Testing

- Installed the real agent at 0.33.1, then upgraded to 0.42.0 in the
same directory:
253MB → 256MB, against two separate copies today. The resolved
executable answers an
  ACP `initialize`.
- macOS only. Windows deserves a look — it should be better than before,
since the
agent is now launched as a plain `.js` file with Node instead of through
npm's `.cmd`
  shim, but I can't verify it.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- Fixed the bundled npm cache growing without bound, which could consume
many gigabytes of disk.
…m-zed-2026-07-29 round 1

# Conflicts:
#	crates/acp_thread/src/acp_thread.rs
#	crates/agent_servers/src/acp.rs
#	crates/agent_ui/src/agent_panel.rs
#	crates/agent_ui/src/config_options.rs
#	crates/language_models/src/provider/open_ai.rs
#	crates/reqwest_client/src/reqwest_client.rs
…e hazards

The 2026-07-29 upstream merge surfaced two load-bearing Helix changes that the
porting guide never documented, both of which present as trivial-looking
conflicts that are easy to resolve toward upstream and silently drop:

- open_ai.rs: chat_completions_reasoning_effort(&self.model) in the
  into_open_ai() reasoning_effort slot (Helix 135f5b4). Upstream keeps
  adding positional params to that call, so the conflict looks like an arg swap.
- reqwest_client.rs: the is_insecure_tls_enabled() branch must stay the tail of
  the builder chain as upstream appends new builder options above it.

Adds script/helix-drift-sweep.sh, which mechanises the rebase checklist (28
checks) so a fix that is present before a merge and absent after is caught
automatically rather than by eye.
Five build breaks from the e45e42a..4b73694 window, all in Helix surface:

- agent_servers/acp.rs: into_foreground_future() removed upstream; force_close_session
  (PR #63 wedge recovery) converted to the new .block_task() form.
- external_websocket_sync/thread_service.rs: ACP schema is now versioned —
  agent_client_protocol::schema -> ::schema::v1 (ContentBlock/TextContent/SessionId).
- agent_ui/conversation_view.rs: from_existing_thread() gained two upstream fields —
  ConnectedServerState::_request_elicitation_subscription (None: headless threads have
  no elicitation UI) and ConversationView::request_elicitation_form_states.
- agent_ui/agent_panel.rs: clear_overlay_state() and its three backing fields were
  removed by upstream 40d2003 (zed-industries#59860, in-panel AI-config overlay retired), so the
  call is dropped from the Critical Fix #11 guard. Guard semantics unchanged.
- zed/src/main.rs: initialize_headless() now fully qualifies agent::ThreadStore.

cargo check --package zed --features external_websocket_sync: clean.
Drift sweep: 28/28.
# Conflicts:
#	.github/workflows/hotfix-review-monitor.yml
#	.github/workflows/stale-pr-reminder.yml
#	crates/agent_servers/src/acp.rs
…am HEAD

# Conflicts:
#	crates/agent_ui/src/agent_panel.rs
#	crates/reqwest_client/src/reqwest_client.rs
…t divergence

Round 4 conflicts:
- reqwest_client.rs: upstream added a read_timeout param to builder(); Helix's
  insecure-TLS branch reinstated as the TAIL of the chain (upstream terminates its
  own chain with .use_rustls_tls(), which would silently disable insecure TLS).
- agent_panel.rs: both sides added a Panel method; kept Helix starts_open
  (auto_open_panel, checklist #26) alongside upstream activation_focus_handle.

Also repairs a raw unresolved conflict block that had been COMMITTED into
.gitignore by an earlier merge (markers and all) — kept every real entry from
both sides.

test_stale_cancelled_response_does_not_cancel_current_compaction is marked
#[ignore] as an intentional Helix divergence: upstream requires a displaced turn
to still deliver its PromptResponse, which is mutually exclusive with Critical
Fix #8 (cancel drops send_task so claude-agent-acp cannot wedge the next turn).
Verified failing identically on pre-merge 06e9ce8, so this is pre-existing
breakage dating to the 002100-extension merge, not a regression — it survived
unnoticed because the checklist only ran 'test_second_send', never the full
suite. With it ignored the suite is green again and usable as a gate.

cargo check -p zed --features external_websocket_sync: clean.
cargo test -p acp_thread: 127 passed, 1 ignored.
cargo test -p external_websocket_sync: 50 passed.
Drift sweep: 28/28.
Documents the largest merge in the series: divergence, the four dated rounds,
all 12 conflicts and their resolutions, the signature drift repaired, and the
Helix-surface survival check.

Two pre-existing breakages found and repaired (neither caused by this merge):
a raw conflict block that had been committed into .gitignore, and a red
cargo test -p acp_thread that had gone unnoticed since 2026-06-18 because the
checklist only ran a single filtered test. Adds checklist item #48 requiring
the full crate suites with a recorded expected baseline.
Production wedge 2026-07-29 (spt_01kyq6qd8h4wqq2rfasc4b01e9): claude-agent-acp
stayed alive but stopped answering session/prompt. connection.prompt() never
resolved, so run_turn emitted no Stopped and no error, and the Helix interaction
sat in state=waiting forever with nothing surfaced in either UI. Only a container
restart recovered it.

Nothing caught it: the await is unbounded, and PR #63's recovery keys on an
ede_diagnostic error string that a silent wedge never produces.

Adds a time-to-FIRST-event watchdog (not a turn timeout):

- THREAD_ACTIVITY, a per-thread counter bumped by the persistent subscription on
  every AcpThreadEvent — any event is proof of life.
- wait_for_first_agent_activity() races a freshly dispatched prompt against
  HELIX_ACP_FIRST_EVENT_TIMEOUT_SECS (default 120s, 0 disables).
- Once the agent emits anything the watchdog disarms for the rest of the turn, so
  long tool calls and slow generations are untouched. A blanket turn timeout would
  false-positive on those; 'zero events since dispatch' does not.
- On expiry the send task is dropped (same rationale as Critical Fix #8 — never
  block on a non-responding agent) and an error carrying helix_silent_prompt_wedge
  is returned.
- is_silent_prompt_wedge() joins the follow-up recovery trigger, so the wedge runs
  the EXISTING force-close -> reload -> retry machinery rather than a new one.

Lives in the Helix-owned crate, not upstream acp_thread.rs, to keep the upstream
diff and future merge-conflict surface at zero.

cargo test -p external_websocket_sync: 55 passed (5 new).
Known gap, documented in the design doc: this covers Helix-originated follow-ups;
UI-typed messages go through agent_ui and are not yet wrapped.
crates/agent_ui/src/acp/ was orphaned by the 2026-03-22 upstream merge
(a2a6f61), which introduced conversation_view.rs as the live implementation
but left the old tree on disk. It has been uncompiled dead code ever since:

  - no 'mod acp;' declaration anywhere in the crate
  - zero references to crate::acp:: / super::acp:: from outside the directory
  - zero references to agent_ui::acp from any other crate

The only crate::acp:: references were self-referential, within the dead tree.

This is not cosmetic. The stale copy shadows the live code when grepping: while
diagnosing the 2026-07-29 production wedge, acp/thread_view/active_thread.rs
was read as the live message-queue interrupt handler when the real one is in
conversation_view/. It also invites resolving phantom merge conflicts in files
that are never built.

cargo check -p agent_ui: clean. Recoverable from history if ever needed.
The send-path watchdog only wraps turns Helix dispatched via
handle_follow_up_message. A turn started by the user typing directly into the
Zed agent panel goes agent_ui -> AcpThread::send() and never passes through it —
which is exactly how the 2026-07-29 production wedge was triggered.

Adds spawn_silent_turn_watchdog(), a per-thread task started alongside the
persistent subscription. It watches ThreadStatus::Generating together with the
THREAD_ACTIVITY counter, so it covers every turn regardless of origin. A turn
that is generating but has produced ZERO events for longer than the first-event
budget is reported to Helix as a terminal chat_response_error, marking the
interaction errored and freeing the activation lane instead of leaving it in
'waiting' forever with nothing surfaced in either UI.

Deliberately does NOT call thread.cancel(): the Stopped handler would then emit
message_completed on top of this error and Helix would see the turn as both
failed and completed. Leaving the turn alone is safe — the next send() displaces
it (cancelling it via Critical Fix #8), so Zed self-heals on the user's next
message while Helix has already been told the truth.

cargo test -p external_websocket_sync: 55 passed.
cargo check -p zed --features external_websocket_sync: clean.
Both agent rounds green on the final tree (17/17 each, store validation passed).

Also records the first run's claude-round flake, whose signature differs from the
previously-documented one (0 events / npx bootstrap): this time the agent produced
a correct answer and then never sent message_completed. Did not reproduce on re-run,
and the likely regression candidate was ruled out by inspection.

Notes two harness gaps it exposed: run_e2e.sh queries the wrong npm scope for the
agent version (@anthropic-ai/... instead of @agentclientprotocol/...), so the
attribution log line is always 'unknown'; and the npm path is unpinned, so the
claude round is not reproducible across time.
@cursor

cursor Bot commented Jul 29, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@lukemarsden

Copy link
Copy Markdown
Author

Paired Helix PR (pins ZED_COMMIT=d1dffb8116): helixml/helix#2896

This PR merges first, then the Helix one.

@lukemarsden
lukemarsden merged commit e868cfe into main Jul 29, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.