Skip to content

Merge upstream-main into main#37

Open
nicosuave wants to merge 395 commits intomainfrom
merge-upstream-main
Open

Merge upstream-main into main#37
nicosuave wants to merge 395 commits intomainfrom
merge-upstream-main

Conversation

@nicosuave
Copy link
Member

Summary

  • Syncs with ghostty-org/ghostty (88 new upstream commits)
  • Connects the full upstream commit DAG to Ghostree's history, which should reduce GitHub's inflated "behind" count caused by early squash merges
  • Adds anti-squash rule to AGENTS.md to prevent this from recurring

Upstream highlights

  • Window positioning/cascading fixes
  • progress-style config option
  • Key equivalent dispatch improvements
  • Shell integration prompt handling rewrite
  • MacOSTitlebarStyle enum (replaces raw strings)
  • New ConfigTests, UserDefaults+Extension
  • Harfbuzz shaper refactor, PageList improvements

Ghostree customizations preserved

  • Branding, bundle IDs (dev.sidequery.Ghostree)
  • Worktrunk sidebar, TerminalGlassContainer protocol
  • Agent dock badges, CI workflows (GitHub-hosted runners)
  • All AGENTS.md safeguards

mitchellh and others added 30 commits March 2, 2026 07:32
… char (ghostty-org#11134)

printCell, when overwriting a wide cell with a narrow cell at x<=1 and
y>0, unconditionally sets the last cell of the previous row to .narrow.
This is intended to clear a spacer_head left by a wrapped wide char, but
the cell could be a spacer_tail if a wide char fit entirely on the
previous row. Setting a spacer_tail to .narrow orphans the preceding
.wide cell, which later causes an integrity violation in insertBlanks
(assert that the cell after a .wide is .spacer_tail).

Fix by guarding the assignment so it only fires when the previous row's
last cell is actually a .spacer_head. The same fix is applied in both
the .wide and .spacer_tail branches of printCell.

Found by AFL++ stream fuzzer. ghostty-org#11109
resizeWithoutReflowGrowCols has a fast path that reuses existing page
capacity when growing columns: it simply bumps page.size.cols without
touching cell data. If any row has a spacer_head at the old last column
(from a wide char that did not fit), that cell is no longer at the end
of the now-wider row, causing a page integrity violation.

Fix by checking for spacer_head cells at the old last column before
taking the fast path. If any are found, fall through to the slow path
which handles spacer heads correctly via cloneRowFrom.

Found by AFL++ stream fuzzer. ghostty-org#11109
When deleteLines or insertLines count >= scroll region height, all rows
go through the clear-only path (no shifting). This path did not call
rowWillBeShifted, leaving orphaned spacer_tail cells when wide characters
straddled the right margin boundary, causing a "spacer tail not following
wide" page integrity violation.

Add rowWillBeShifted before clearCells in the else branch of both
functions.

Found via AFL++ fuzzing. ghostty-org#11109
…g#11135)

resizeWithoutReflowGrowCols has a fast path that reuses existing page
capacity when growing columns: it simply bumps page.size.cols without
touching cell data. If any row has a spacer_head at the old last column
(from a wide char that did not fit), that cell is no longer at the end
of the now-wider row, causing a page integrity violation.

Fix by checking for spacer_head cells at the old last column before
taking the fast path. If any are found, fall through to the slow path
which handles spacer heads correctly via cloneRowFrom.

Found by AFL++ stream fuzzer. ghostty-org#11109
…hostty-org#11136)

When deleteLines or insertLines count >= scroll region height, all rows
go through the clear-only path (no shifting). This path did not call
rowWillBeShifted, leaving orphaned spacer_tail cells when wide
characters straddled the right margin boundary, causing a "spacer tail
not following wide" page integrity violation.

Add rowWillBeShifted before clearCells in the else branch of both
functions.

Found via AFL++ fuzzing. ghostty-org#11109
When insertBlanks clears the entire region from cursor to the right
margin (scroll_amount == 0), a wide character whose head is at the right
margin gets cleared but its spacer_tail just beyond the margin is left
behind, causing a "spacer tail not following wide" page integrity
violation.

Move the right-margin wide-char cleanup from inside the scroll_amount >
0 block to before it, so it runs unconditionally — matching the
rowWillBeShifted pattern of cleaning up boundary-straddling wide chars
up front.

Found via AFL++ fuzzing. ghostty-org#11109
Triggered by [discussion
comment](ghostty-org#11128 (comment))
from @mitchellh.

Vouch: @noib3

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…hostty-org#11137)

When insertBlanks clears the entire region from cursor to the right
margin (scroll_amount == 0), a wide character whose head is at the right
margin gets cleared but its spacer_tail just beyond the margin is left
behind, causing a "spacer tail not following wide" page integrity
violation.

Move the right-margin wide-char cleanup from inside the scroll_amount >
0 block to before it, so it runs unconditionally — matching the
rowWillBeShifted pattern of cleaning up boundary-straddling wide chars
up front.

Found via AFL++ fuzzing. ghostty-org#11109
When cursor-click-to-move is set to false, disable all prompt
click-to-move mechanisms including shell-native methods such as OSC 133
cl= (arrow key synthesis) and click_events. 

I forgot to port this config over when we did the OSC133 stuff.

Also update the config documentation to accurately describe the current
behavior.

Fixes ghostty-org#11138
…y-org#11141)

When cursor-click-to-move is set to false, disable all prompt
click-to-move mechanisms including shell-native methods such as OSC 133
cl= (arrow key synthesis) and click_events.

I forgot to port this config over when we did the OSC133 stuff.

Also update the config documentation to accurately describe the current
behavior.

Fixes ghostty-org#11138
This PR implements the fix discussed in
ghostty-org#11128
This PR implements the fix discussed in
ghostty-org#11128.

Before:

<img width="818" height="96" alt="before"
src="https://github.com/user-attachments/assets/788f981f-3d1b-4c60-bf85-0c297641cae7"
/>

After:

<img width="813" height="93" alt="after"
src="https://github.com/user-attachments/assets/a530015a-053a-4680-9a85-812aa8df3d91"
/>
)

Fixes ghostty-org#7937

Added `computeInitialSize` to GTK `Surface` and call it in GTK
`Application` before the first `present()`, so the window manager
centers the correct size on initial show.

The issue occurs because the core `Surface.recomputeInitialSize()` runs
only after the renderer is initialized. In GTK, the `GLArea` isn’t
realized until after `present()`, so the initial size arrives too late
for WM centering.

**Limitations**: when we precompute size before `present()` we do not
have access to padding, so the sizing will be very slightly off... but
since it is only off a few pixels I was unable to tell visually that it
wasn't perfectly centered.

**Other thoughts**: I was hesitant to make changes to core `Surface`
because the issue is Linux-specific, but it may make sense to extract a
helper from `recomputeInitialSize` to avoid duplicating the sizing math.

**AI Disclosure:** I used AI to explore the project, help with any
language / API questions (I've never used zig before and rarely use
gtk), and make implementation suggestions.
…ghostty-org#11147)

This fixes ghostty-org#11146 and also ghostty-org#10993. Updated the comments added in ghostty-org#11052.

> After finishing editing when the window resigns as the key window,
using `labelFrame.minY` is fine with the same usage as ghostty-org#10993, but when
double-clicking with text selected it will move up again 🤷🏻‍♂️.

This makes focus state more accurate with cursor shape on the surface,
when editing the title for a tab in another window group.

[Incorrect
example](https://github.com/user-attachments/assets/c3c4e774-a683-44e7-9bb6-3be79ac72ec2)
I'm running this now, 10 minutes with nothing but I figure this is a big
enough target we should also add this.
When the kitty keyboard protocol "report all keys as escape codes" mode
was active, composed/IME text (e.g. from dead keys or compose sequences)
was silently dropped. 

This happened because the composed text is sent within our GTK apprt
with key=unidentified and no unshifted_codepoint, so no kitty entry was
found and the encoder returned without producing any output. The
plain-text fallback was also skipped because report_all bypasses it.

Send composed text as raw UTF-8 when no kitty entry is found, matching
the behavior of Kitty on Linux for me.

Fixes ghostty-org#10049
When the kitty keyboard protocol "report all keys as escape codes" mode
was active, composed/IME text (e.g. from dead keys or compose sequences)
was silently dropped.

This happened because the composed text is sent within our GTK apprt
with key=unidentified and no unshifted_codepoint, so no kitty entry was
found and the encoder returned without producing any output. The
plain-text fallback was also skipped because report_all bypasses it.

Send composed text as raw UTF-8 when no kitty entry is found, matching
the behavior of Kitty on Linux for me.

Fixes ghostty-org#10049
Because of the global shared state that FontConfig maintains, FontConfig
must be linked dynamically to the same system FontConfig shared library
that GTK uses. Ghostty's default has been changed to always link to the
system FontConfig library on non-macOS systems. If that is overridden
(by specifying `-fno-sys=fontconfig` during the build) Ghostty may crash
when trying to locate glyphs that are not available in the default font.

Fixes ghostty-org#10432
…hostty-org#11152)

Because of the global shared state that FontConfig maintains, FontConfig
must be linked dynamically to the same system FontConfig shared library
that GTK uses. Ghostty's default has been changed to always link to the
system FontConfig library on non-macOS systems. If that is overridden
(by specifying `-fno-sys=fontconfig` during the build) Ghostty may crash
when trying to locate glyphs that are not available in the default font.

Fixes ghostty-org#10432
Extends the macOS bell implementation to support the `audio` bell
feature by playing a user-specified audio file via NSSound.

Previously, macOS only supported the `system` feature (NSSound.beep()).
This change adds support for:
- `audio` bell feature: plays the file at `bell-audio-path` using
  NSSound, respecting the `bell-audio-volume` setting
- Adds `cval()` to the `Path` type so it can be returned via the C API

Also removes the "(GTK only)" restriction from `bell-audio-path` and
`bell-audio-volume` documentation, as these options now work on macOS.

Example config:
  bell-features = audio
  bell-audio-path = /System/Library/Sounds/Glass.aiff
  bell-audio-volume = 0.8
Triggered by
[comment](ghostty-org#11154 (comment))
from @mitchellh.

Vouch: @alaasdk

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
mitchellh and others added 29 commits March 11, 2026 10:02
Claude wrote the fail path in the UI tests, or you can easily reproduce
this manually. This is kinda a regression after ghostty-org#11322, since we are not
delaying the frame update anymore, which exposes some of the "flaws" of
the previous implementation.

The following three commits fix this step by step:
- We shouldn't save intermediate frames when the window is loading,
which is triggered by `windowDidResize` and `windowDidMove` during the
process.
- We should set the initial position (from the config) after the window
is loaded.
- A small refactor on `LastWindowPosition` to support restoring the
window frame under certain conditions.


https://github.com/user-attachments/assets/6f90f9a5-653d-4146-95c6-8e5c69bda656



### AI Disclosure

Claude helped me write the UI tests.
Bump of `zig-overlay`, allowing us to drop flake-utils from the flake
inputs. :)
Fixes ghostty-org#11379

For this pass, I made it a very simple "within 20%" (height-wise) of the
split handle. There is no horizontal component. I want to find the right
balance between always visible (today mostly) to only visible on direct
hover, because I think it'll be too hard to discover on that far right
side.
…-org#11383)

Fixes ghostty-org#11379

For this pass, I made it a very simple "within 20%" (height-wise) of the
split handle down. There is no horizontal component. I want to find the
right balance between always visible (today mostly) to only visible on
direct hover, because I think it'll be too hard to discover on that far
right side.
Triggered by [discussion
comment](ghostty-org#11388 (comment))
from @jcollie.

Vouch: @wyounas

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 8.0.0 to 8.0.1.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](actions/download-artifact@70fc10c...3e5f45b)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 8.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Add option to disable OSC 9;4 ConEmu progress bars via config.

Fixes ghostty-org#11241
Fixes ghostty-org#11396

Track menu items populated from Ghostty keybind actions and only trigger
those from SurfaceView performKeyEquivalent. This avoids app-default
shortcuts such as Hide from pre-empting explicit keybinds.
…tty-org#11399)

Bumps
[actions/download-artifact](https://github.com/actions/download-artifact)
from 8.0.0 to 8.0.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/download-artifact/releases">actions/download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v8.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Support for CJK characters in the artifact name by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/download-artifact/pull/471">actions/download-artifact#471</a></li>
<li>Add a regression test for artifact name + content-type mismatches by
<a href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a>
in <a
href="https://redirect.github.com/actions/download-artifact/pull/472">actions/download-artifact#472</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/download-artifact/compare/v8...v8.0.1">https://github.com/actions/download-artifact/compare/v8...v8.0.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/download-artifact/commit/3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c"><code>3e5f45b</code></a>
Add regression tests for CJK characters (<a
href="https://redirect.github.com/actions/download-artifact/issues/471">#471</a>)</li>
<li><a
href="https://github.com/actions/download-artifact/commit/e6d03f67377d4412c7aa56a8e2e4988e6ec479dd"><code>e6d03f6</code></a>
Add a regression test for artifact name + content-type mismatches (<a
href="https://redirect.github.com/actions/download-artifact/issues/472">#472</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/download-artifact/compare/70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3...3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/download-artifact&package-manager=github_actions&previous-version=8.0.0&new-version=8.0.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
…-org#11403)

Fixes ghostty-org#11396

Track menu items populated from Ghostty keybind actions and only trigger
those from SurfaceView performKeyEquivalent. This avoids app-default
shortcuts such as Hide from pre-empting explicit keybinds.
Adds progress-style config to control OSC 9;4 progress bar visibility.
Defaults to true, set false to hide.

Fixes ghostty-org#11241

AI Disclosure: Claude Code (Opus 4.6) used for codebase exploration,
code review, and testing assistance. All code written and reviewed by
hand.
Depends on ghostty-org#11417

Moved positioning part from `windowDidLoad` to `showWindow` to make new
users happy. Also deleted `initialFrame`, since we don't need it
anymore.
Added test case for cascading **without moving previous window**, ghostty-org#11161
will follow up for more accurate cascading after this.

Fixed window cascading after last pr, now we should perform cascading
**after** showing the window.
Make it smaller and add comparisons between y values
Syncs with ghostty-org/ghostty up to e11f350..597e8cf (88 commits).

Upstream changes include: window positioning/cascading fixes,
progress-style config option, key equivalent dispatch improvements,
shell integration prompt handling rewrite, MacOSTitlebarStyle enum,
ConfigTests, UserDefaults+Extension, harfbuzz shaper refactor,
PageList improvements, and various bug fixes.

All Ghostree customizations preserved: branding, bundle IDs,
worktrunk sidebar, TerminalGlassContainer protocol, agent dock
badges, CI workflows (GitHub-hosted runners), and AGENTS.md
anti-squash rule.
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 11eacca9b2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 6455 to 6457
.{ .copy_to_clipboard = .mixed },
.{ .performable = true },
);

Choose a reason for hiding this comment

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

P1 Badge Keep default copy shortcut non-performable

Making the default copy binding performable changes behavior when nothing is selected: copy_to_clipboard returns false in that case, so this keypress is now unconsumed and falls through to terminal input. On Linux/Windows, pressing the default Ctrl+Shift+C with no selection can therefore propagate as Ctrl+C and interrupt the foreground process, which is a regression from the previous always-consumed copy shortcut.

Useful? React with 👍 / 👎.

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.