Skip to content

Sync with upstream ghostty (1,150 commits)#22

Open
lawrencecchen wants to merge 1166 commits into
mainfrom
cmux-upstream-sync-0330
Open

Sync with upstream ghostty (1,150 commits)#22
lawrencecchen wants to merge 1166 commits into
mainfrom
cmux-upstream-sync-0330

Conversation

@lawrencecchen
Copy link
Copy Markdown

@lawrencecchen lawrencecchen commented Mar 30, 2026

Summary

Rebases cmux patches onto latest upstream ghostty (upstream/main), catching up from Feb 17 to Mar 30.

This brings in the fix for the click-after-tab-switch infinite scroll bug (manaflow-ai/cmux#1199) via upstream ghostty-org#11167.

Carried forward (13 cmux patches):

  • Display link restart after display ID change
  • Reduce transient blank/scaled frames during resize
  • Top-left gravity for stale-frame replay
  • OSC 99 notification parser
  • Theme picker (7 commits)
  • Mode 2031 color scheme fixes (2 commits)

Dropped:


Summary by cubic

Sync cmux with upstream ghostty (through 2026‑03‑30) to fix the post‑tab‑switch infinite scroll bug and ship major libghostty/Windows upgrades, plus a README/roadmap overhaul making libghostty a first‑class target. Also adds a top‑level CMake wrapper and many C/CMake examples for easier embedding.

  • New Features

    • Stream: renamed to TerminalStream with effect callbacks and replies for DECRQM, DSR (operating status, cursor, color scheme), device attributes (DA1/DA2/DA3), kitty keyboard, XTVERSION, ENQ, window title, and size (XTWINOPS).
    • C API: ghostty_alloc/ghostty_free; ghostty_terminal_set options for write_pty, bell, title_changed, enquiry, xtversion, size, color_scheme, and device_attributes.
    • Render API: per‑cell resolved RGB fg_color/bg_color in GhosttyRenderStateRowCellsData (invalid when unset so callers can fall back).
    • CMake: top‑level wrapper delegating to zig build -Demit-lib-vt, installable shared/static ghostty-vt targets, and ghostty-vt-config.cmake for find_package/FetchContent; Windows import‑lib placement and Ninja OUTPUT fixes.
    • Examples: new C API samples (encode key/mouse/focus, formatter/render, grid traverse, colors, effects, modes, paste utilities, size‑report, build‑info, stream) plus CMake shared/static projects; static lib built for wasm.
    • GTK: open URLs via portals with lifecycle, fallback, and error‑handling improvements.
  • Build & CI

    • Windows/MSVC: stable libghostty-vt builds/tests via VirtualAlloc paging, CRLF X11 color parsing, Windows path/colon config parsing, ssize_t typedef, default MSVC ABI and C++17 flags, LLVM backend, skip/bundle fixes for compiler_rt/ubsan_rt, link ntdll/kernel32; fixed zlib, freetype (headers/enums), glslang (C++17, no linkLibCpp), oniguruma; helpgen/framegen stdout/scandir fixes; increased comptime quota; static lib named ghostty-vt-static.lib.
    • CI/Tooling: new test-lib-vt and a “skip” gating job; removed continue‑on‑error on Windows; action pins updated; Vouch CODEOWNERS sync workflow; SwiftLint config/checks; .gitattributes line‑ending rules; README/HACKING updates.

Written for commit 40c3dcd. Summary will update on new commits.

mitchellh and others added 30 commits March 22, 2026 07:58
The README hasn't been updated in years basically! 

This updates the README to make libghostty a first class citizen of the
project and to update our roadmap and goals for the project to more
accurately reflect our current state and future plans.
The README hasn't been updated in years basically! 

This updates the README to make libghostty a first class citizen of the
project and to update our roadmap and goals for the project to more
accurately reflect our current state and future plans.

I notably updated our roadmap to be more accurate to our state, e.g.
we're stable now. I removed Windows because it's not a short term focus
and I think libghostty is more important and enables that ecosystem a
lot more (libghostty itself being already compatible with Windows). I
also expanded on "fancy features" and clarified its to make
Ghostty-specific sequences.
- Token is formatted without allocation
- Reusable function for formatToken
- Tests in portal.zig are actuall included now
Triggered by
[comment](ghostty-org#11754 (comment))
from @mitchellh.

Vouch: @tdgroot

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Triggered by
[comment](ghostty-org#11771 (comment))
from @jcollie.

Vouch: @deblasis

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Triggered by
[comment](ghostty-org#11768 (comment))
from @jcollie.

Vouch: @lynicis

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This is a continuation of the solid work done by @jcollie in PR ghostty-org#7864. I
checked with him if I could take over to continue the implementation.

His changes of last year have been adapted to be compatible with the
current GTK implementation. Aside from just "making it work", I also
dived into the portals and OpenURI implementation and made some
improvements there.

Notable improvements were:
- Improved lifecycle management of glib resources in the OpenURI
implementation
- More forgiving error handling in OpenURI implementation by adding more
fallbacks
- Fixed some memory leaks
- Less memory allocations in Portals implementation
- Added tests for building the Portals request path

Fixes ghostty-org#5991
A static libghostty-vt is also useful for wasm targets, as that allows
linking with an application into a larger wasm module.

See
ghostty-org#11729 (comment)
Previously WindowPaddingBalance was defined inside Config.zig, which
meant tests for renderer sizing had to pull in the full config
dependency. Move the enum into renderer/size.zig as PaddingBalance
and re-export it from Config so the public API is unchanged. This
lets size.zig tests run without depending on Config.
The inline else switch in each C API getter expands the .invalid
case, which has OutType void. When called with .invalid and a null
out pointer, the @ptrCast(@aligncast(out)) panics before getTyped
can return early.

Handle .invalid explicitly in the outer switch of every getter to
short-circuit before the pointer cast. This affects build_info,
cell, row, terminal, osc, and render (three getters).
Add a new CI job that runs `zig build test-lib-vt` to test the
lib-vt build step. The job mirrors the existing test job structure
with the same nix/cachix setup and skip conditions. It is also
added to the required checks list.
The colors_get function used structSizedFieldFits to guard the
palette copy, which required the entire palette array to fit in the
provided size. This prevented partial palette writes when the caller
passed a truncated sized struct, since the guard failed even though
the inner code already handled partial copies correctly. Remove the
outer guard so the existing partial-copy logic applies.

The setopt_from_terminal test expected alt_esc_prefix to be false on
a fresh terminal, but the mode definition in modes.zig sets its
default to true. Update the test expectation to match.
- Our `checkGhosttyH` calls need to be guarded on building Ghostty app
which has it
- Move FileFormatter to its own file to avoid poisoning test refs with
Config.zig which pulls in the world
- Move WindowPaddingBalance to renderer to avoid pulling in Config.zig
- Add a `zig build test-lib-vt` CI job
Rename build-windows to build-libghostty-vt-windows to reflect that
it only builds and tests libghostty-vt for now, and move it next to
the other build-libghostty-vt jobs.

Replace the manual PowerShell zig download/install with mlugg/setup-zig,
which auto-detects the version from build.zig.zon and handles caching.
Upgrade the runner from windows-2022 to windows-2025. Remove the
generated-script-to-swallow-errors pattern in favor of direct zig
build commands.
Extract the platform-specific page backing memory allocation into
AllocPosix and AllocWindows structs behind a PageAlloc comptime
switch. Previously, POSIX mmap calls were inlined at each call
site. This adds a Windows VirtualAlloc implementation and routes
all allocation through PageAlloc.alloc/free, making the backing
memory strategy consistent and easier to extend.
The X11 color map parser in x11_color.zig uses @embedfile to load
rgb.txt at comptime, then splits on \n. On Windows, git may check
out rgb.txt with CRLF line endings, leaving a trailing \r on each
line. This caused color names to be stored as e.g. "white\r" instead
of "white", so all X11 color lookups failed at runtime.

Strip trailing \r from each line before parsing. Also mark rgb.txt
as -text in .gitattributes to prevent line ending conversion in
future checkouts.
…y-vt (ghostty-org#11781)

Our Windows build has been broken for a _long_ time. It hasn't actually
worked and our CI was falsely passing when it was actually failing to
build/test. This PR fixes that and fixes the issues it found so
`libghostty-vt` can build and pass tests.

**This is only for libghostty!** I'd still like to expand our _test_
coverage to all of Ghostty for Windows but libghostty is more important
for that platform in the short term and it's an incremental piece of
work.

A couple windows compatibility issues fixed:

- `terminal.Page` uses `VirtualAlloc` on Windows (thanks @deblasis)
- Our rgb.txt loading was not resilient to CRLF endings
On Windows, shared libraries (DLLs) require an import library (.lib)
for linking, and the DLL itself is placed in bin/ rather than lib/ by
the Zig build. The CMake wrapper was missing IMPORTED_IMPLIB on the
shared imported target, causing link failures, and assumed the shared
library was always in lib/.

Add GHOSTTY_VT_IMPLIB for the import library name, set IMPORTED_IMPLIB
on the ghostty-vt target, and fix the shared library path to use bin/
on Windows. Install the DLL and PDB to bin/ and the import library to
lib/ following standard Windows conventions. Apply the same fixes to
ghostty-vt-config.cmake.in for the find_package path.
Use writerStreaming() instead of writer() for stdout in helpgen and
main_build_data. The positional writer calls setEndPos/ftruncate in
end(), which fails on Windows when stdout is redirected via
captureStdOut() because ftruncate maps INVALID_PARAMETER to
FileTooBig. Streaming mode skips truncation entirely since stdout
is inherently a sequential stream.

Replace scandir with opendir/readdir plus qsort in framegen since
scandir is a POSIX extension not available on Windows.
Add a "Run Example" step to the build-examples-cmake-windows job
so that each CMake example is executed after it is built, verifying
the resulting binaries actually work. The executable name is derived
from the matrix directory name by replacing hyphens with underscores,
matching the project convention.
ghostty-vouch Bot and others added 16 commits March 30, 2026 20:50
Triggered by
[comment](ghostty-org#11999 (comment))
from @jcollie.

Vouch: @BarutSRB

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Apple's recent libtool can warn about misaligned 64-bit archive members
and silently drop them when merging static libraries. In Ghostty this
showed up in the Darwin libtool step that builds libghostty-fat.a.

Normalize each input archive by copying it and running ranlib on the
copy
before handing it to libtool. That rewrites the archive into a layout
Apple's linker tools accept without flattening members through the
filesystem or changing Ghostty's archive format.
…org#11999)

## Root cause

Zig 0.15.2 can produce macOS `.a` archives where some 64-bit Mach-O
members are only 4-byte aligned inside the archive. Recent Apple
`libtool -static` does not handle that layout correctly: it emits `not
8-byte aligned` warnings and, in the failing case, silently drops those
members when creating the combined static library.

In Ghostty, this happened in the Darwin `libtool` merge step that builds
`libghostty-fat.a`. The x86_64 input `libghostty.a` still contained the
expected `libghostty_zcu.o` and about 97 exported `_ghostty_` symbols,
but after `libtool -static` the output archive contained only 4 SIMD
symbols because `libghostty_zcu.o` had been discarded. The same warning
pattern also appeared in third-party input archives such as
`libfreetype.a` and `libz.a`, so this was not only a `libghostty.a`
problem.

## What needed to be done

The inputs to Apple `libtool` needed to be normalized before they were
merged.

The safest fix is to copy each input archive and run `ranlib -D` on the
copy before passing it to `libtool`. `ranlib` rewrites the archive into
a form that Apple’s linker tools accept, fixing the alignment/layout
issue without changing the archive’s semantic contents.

## Why this approach

An `ar x` -> `ar rcs` workaround can also make the warnings go away, but
it is a broader and riskier transformation. Extracting archive members
into a flat directory is not semantics-preserving:

- duplicate member basenames can collide
- non-`.o` members can be lost
- member order can change

That means an `ar`-based rearchive can silently change valid archives
while fixing alignment. `ranlib -D` avoids those hazards because it
rewrites the archive in place instead of flattening it through the
filesystem.

`-D` is also important because plain `ranlib` is not deterministic. In
local testing, `ranlib -D` still fixed the alignment issue, preserved
all 97 `_ghostty_` symbols, produced no `libtool` warnings, and was
byte-stable across repeated runs.

## Validation

This was reproduced directly:

- before normalization, running `libtool -static` on the affected x86_64
`libghostty.a` produced a `libghostty_zcu.o not 8-byte aligned` warning
and the output archive dropped from 97 `_ghostty_` symbols to 4
- after `ranlib -D`, the same `libtool -static` command preserved all 97
`_ghostty_` symbols and emitted no alignment warnings

After applying the normalization step, a clean `zig build` succeeded,
and the final macOS xcframework archive contained 97 `_ghostty_` symbols
in both the `x86_64` and `arm64` slices.

## Summary

This was not a Metal issue, not an Xcode project issue, and not a
stale-cache issue. The actual root cause was an Apple `libtool`
interoperability problem with Zig-produced macOS archives. The required
fix was to normalize each archive before the Darwin `libtool` merge
step, and `ranlib -D` is the least invasive way to do that while
preserving archive semantics.
When changeConditionalState returns null (no theme-conditional config
rules), the Termio DerivedConfig inherits conditional_state from the
app-level config which defaults to .light and is never updated. This
caused colorSchemeReportLocked to always report light mode.

Fix: override conditional_state with the surface's own
config_conditional_state after creating the Termio DerivedConfig.
* Add cmux theme picker helper hooks

* Fix cmux theme picker preview writes

* Improve cmux theme picker footer contrast

* Respect system theme in cmux picker

* Skip theme detection in cmux picker

* Match Ghostty theme picker startup

* Harden cmux theme override writes

* Fix DECRPM mode 2031 reporting wrong color scheme after config reload

When changeConditionalState returns null (no theme-conditional config
rules in the user's config), the Termio DerivedConfig inherits its
conditional_state from the app-level config, which defaults to .light
and is never updated. This caused colorSchemeReportLocked to always
report light mode even when the surface's own color scheme was dark.

Fix: after creating the Termio DerivedConfig, override its
conditional_state with the surface's own config_conditional_state.
This ensures the DECRPM mode 2031 response matches the actual surface
color scheme.

* Send initial color scheme report when mode 2031 is enabled

Per the mode 2031 spec, the terminal must send an initial DSR 997
report when the mode is enabled via DECSET. Without this, clients
that enable mode 2031 never receive the current color scheme.

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 30, 2026

Important

Review skipped

Too many files!

This PR contains 295 files, which is 145 over the limit of 150.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bdba5d66-a19d-4617-894d-a9765d4fbe48

📥 Commits

Reviewing files that changed from the base of the PR and between cf6c326 and 40c3dcd.

⛔ Files ignored due to path filters (5)
  • dist/cmake/README.md is excluded by !**/dist/**
  • dist/cmake/ghostty-vt-config.cmake.in is excluded by !**/dist/**
  • dist/linux/com.mitchellh.ghostty.metainfo.xml.in is excluded by !**/dist/**
  • dist/linux/ghostty_dolphin.desktop is excluded by !**/dist/**
  • flake.lock is excluded by !**/*.lock
📒 Files selected for processing (295)
  • .agents/commands/gh-issue
  • .agents/skills/writing-commit-messages/SKILL.md
  • .gitattributes
  • .github/VOUCHED.td
  • .github/workflows/flatpak.yml
  • .github/workflows/milestone.yml
  • .github/workflows/nix.yml
  • .github/workflows/release-tag.yml
  • .github/workflows/release-tip.yml
  • .github/workflows/snap.yml
  • .github/workflows/test.yml
  • .github/workflows/update-colorschemes.yml
  • .github/workflows/vouch-check-issue.yml
  • .github/workflows/vouch-check-pr.yml
  • .github/workflows/vouch-manage-by-discussion.yml
  • .github/workflows/vouch-manage-by-issue.yml
  • .github/workflows/vouch-sync-codeowners.yml
  • .gitignore
  • .prettierignore
  • .swiftlint.yml
  • AGENTS.md
  • CMakeLists.txt
  • CODEOWNERS
  • CONTRIBUTING.md
  • HACKING.md
  • README.md
  • build.zig
  • build.zig.zon
  • build.zig.zon.bak
  • build.zig.zon.json
  • build.zig.zon.nix
  • build.zig.zon.txt
  • example/.gitignore
  • example/AGENTS.md
  • example/README.md
  • example/c-vt-build-info/README.md
  • example/c-vt-build-info/build.zig
  • example/c-vt-build-info/build.zig.zon
  • example/c-vt-build-info/src/main.c
  • example/c-vt-cmake-static/CMakeLists.txt
  • example/c-vt-cmake-static/README.md
  • example/c-vt-cmake-static/src/main.c
  • example/c-vt-cmake/CMakeLists.txt
  • example/c-vt-cmake/README.md
  • example/c-vt-cmake/src/main.c
  • example/c-vt-colors/README.md
  • example/c-vt-colors/build.zig
  • example/c-vt-colors/build.zig.zon
  • example/c-vt-colors/src/main.c
  • example/c-vt-effects/README.md
  • example/c-vt-effects/build.zig
  • example/c-vt-effects/build.zig.zon
  • example/c-vt-effects/src/main.c
  • example/c-vt-encode-focus/README.md
  • example/c-vt-encode-focus/build.zig
  • example/c-vt-encode-focus/build.zig.zon
  • example/c-vt-encode-focus/src/main.c
  • example/c-vt-encode-key/README.md
  • example/c-vt-encode-key/build.zig
  • example/c-vt-encode-key/build.zig.zon
  • example/c-vt-encode-key/src/main.c
  • example/c-vt-encode-mouse/README.md
  • example/c-vt-encode-mouse/build.zig
  • example/c-vt-encode-mouse/build.zig.zon
  • example/c-vt-encode-mouse/src/main.c
  • example/c-vt-formatter/README.md
  • example/c-vt-formatter/build.zig
  • example/c-vt-formatter/build.zig.zon
  • example/c-vt-formatter/src/main.c
  • example/c-vt-grid-traverse/README.md
  • example/c-vt-grid-traverse/build.zig
  • example/c-vt-grid-traverse/build.zig.zon
  • example/c-vt-grid-traverse/src/main.c
  • example/c-vt-key-encode/build.zig
  • example/c-vt-key-encode/src/main.c
  • example/c-vt-modes/README.md
  • example/c-vt-modes/build.zig
  • example/c-vt-modes/build.zig.zon
  • example/c-vt-modes/src/main.c
  • example/c-vt-paste/README.md
  • example/c-vt-paste/src/main.c
  • example/c-vt-render/README.md
  • example/c-vt-render/build.zig
  • example/c-vt-render/build.zig.zon
  • example/c-vt-render/src/main.c
  • example/c-vt-sgr/src/main.c
  • example/c-vt-size-report/README.md
  • example/c-vt-size-report/build.zig
  • example/c-vt-size-report/build.zig.zon
  • example/c-vt-size-report/src/main.c
  • example/c-vt-static/README.md
  • example/c-vt-static/build.zig
  • example/c-vt-static/build.zig.zon
  • example/c-vt-static/src/main.c
  • example/c-vt-stream/README.md
  • example/c-vt-stream/build.zig
  • example/c-vt-stream/build.zig.zon
  • example/c-vt-stream/src/main.c
  • example/cpp-vt-stream/README.md
  • example/cpp-vt-stream/build.zig
  • example/cpp-vt-stream/build.zig.zon
  • example/cpp-vt-stream/src/main.cpp
  • example/wasm-key-encode/README.md
  • example/wasm-sgr/README.md
  • example/wasm-vt/README.md
  • example/wasm-vt/index.html
  • example/zig-formatter/src/main.zig
  • example/zig-vt-stream/src/main.zig
  • flake.nix
  • flatpak/zig-packages.json
  • include/ghostty.h
  • include/ghostty/vt.h
  • include/ghostty/vt/allocator.h
  • include/ghostty/vt/build_info.h
  • include/ghostty/vt/color.h
  • include/ghostty/vt/device.h
  • include/ghostty/vt/focus.h
  • include/ghostty/vt/formatter.h
  • include/ghostty/vt/grid_ref.h
  • include/ghostty/vt/key.h
  • include/ghostty/vt/key/encoder.h
  • include/ghostty/vt/key/event.h
  • include/ghostty/vt/modes.h
  • include/ghostty/vt/mouse.h
  • include/ghostty/vt/mouse/encoder.h
  • include/ghostty/vt/mouse/event.h
  • include/ghostty/vt/osc.h
  • include/ghostty/vt/paste.h
  • include/ghostty/vt/point.h
  • include/ghostty/vt/render.h
  • include/ghostty/vt/result.h
  • include/ghostty/vt/screen.h
  • include/ghostty/vt/sgr.h
  • include/ghostty/vt/size_report.h
  • include/ghostty/vt/style.h
  • include/ghostty/vt/terminal.h
  • include/ghostty/vt/types.h
  • include/ghostty/vt/wasm.h
  • macos/.swiftlint.yml
  • macos/AGENTS.md
  • macos/Ghostty-Info.plist
  • macos/Ghostty.sdef
  • macos/Ghostty.xcodeproj/project.pbxproj
  • macos/Ghostty.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
  • macos/GhosttyUITests/GhosttyCommandPaletteTests.swift
  • macos/GhosttyUITests/GhosttyCustomConfigCase.swift
  • macos/GhosttyUITests/GhosttyMouseStateTests.swift
  • macos/GhosttyUITests/GhosttyWindowPositionUITests.swift
  • macos/Sources/App/macOS/AppDelegate+Ghostty.swift
  • macos/Sources/App/macOS/AppDelegate.swift
  • macos/Sources/App/macOS/MainMenu.xib
  • macos/Sources/App/macOS/ghostty-bridging-header.h
  • macos/Sources/App/macOS/main.swift
  • macos/Sources/Features/About/AboutController.swift
  • macos/Sources/Features/About/AboutView.swift
  • macos/Sources/Features/About/AboutViewModel.swift
  • macos/Sources/Features/About/CyclingIconView.swift
  • macos/Sources/Features/App Intents/CloseTerminalIntent.swift
  • macos/Sources/Features/App Intents/CommandPaletteIntent.swift
  • macos/Sources/Features/App Intents/Entities/CommandEntity.swift
  • macos/Sources/Features/App Intents/Entities/TerminalEntity.swift
  • macos/Sources/Features/App Intents/GetTerminalDetailsIntent.swift
  • macos/Sources/Features/App Intents/InputIntent.swift
  • macos/Sources/Features/App Intents/IntentPermission.swift
  • macos/Sources/Features/App Intents/KeybindIntent.swift
  • macos/Sources/Features/App Intents/NewTerminalIntent.swift
  • macos/Sources/Features/App Intents/QuickTerminalIntent.swift
  • macos/Sources/Features/AppleScript/AppDelegate+AppleScript.swift
  • macos/Sources/Features/AppleScript/Ghostty.Input.Mods+AppleScript.swift
  • macos/Sources/Features/AppleScript/ScriptInputTextCommand.swift
  • macos/Sources/Features/AppleScript/ScriptKeyEventCommand.swift
  • macos/Sources/Features/AppleScript/ScriptMouseButtonCommand.swift
  • macos/Sources/Features/AppleScript/ScriptMousePosCommand.swift
  • macos/Sources/Features/AppleScript/ScriptMouseScrollCommand.swift
  • macos/Sources/Features/AppleScript/ScriptRecord.swift
  • macos/Sources/Features/AppleScript/ScriptSurfaceConfiguration.swift
  • macos/Sources/Features/AppleScript/ScriptTab.swift
  • macos/Sources/Features/AppleScript/ScriptTerminal.swift
  • macos/Sources/Features/AppleScript/ScriptWindow.swift
  • macos/Sources/Features/ClipboardConfirmation/ClipboardConfirmationController.swift
  • macos/Sources/Features/ClipboardConfirmation/ClipboardConfirmationView.swift
  • macos/Sources/Features/Colorized Ghostty Icon/ColorizedGhosttyIcon.swift
  • macos/Sources/Features/Command Palette/CommandPalette.swift
  • macos/Sources/Features/Command Palette/TerminalCommandPalette.swift
  • macos/Sources/Features/Custom App Icon/AppIcon.swift
  • macos/Sources/Features/Custom App Icon/ColorizedGhosttyIcon.swift
  • macos/Sources/Features/Custom App Icon/ColorizedGhosttyIconImage.swift
  • macos/Sources/Features/Custom App Icon/ColorizedGhosttyIconView.swift
  • macos/Sources/Features/Custom App Icon/DockTilePlugin.swift
  • macos/Sources/Features/Custom App Icon/Extensions/Notification+AppIcon.swift
  • macos/Sources/Features/Custom App Icon/Extensions/UserDefaults+AppIcon.swift
  • macos/Sources/Features/Global Keybinds/GlobalEventTap.swift
  • macos/Sources/Features/QuickTerminal/QuickTerminalController.swift
  • macos/Sources/Features/QuickTerminal/QuickTerminalPosition.swift
  • macos/Sources/Features/QuickTerminal/QuickTerminalScreen.swift
  • macos/Sources/Features/QuickTerminal/QuickTerminalScreenStateCache.swift
  • macos/Sources/Features/QuickTerminal/QuickTerminalSize.swift
  • macos/Sources/Features/QuickTerminal/QuickTerminalSpaceBehavior.swift
  • macos/Sources/Features/QuickTerminal/QuickTerminalWindow.swift
  • macos/Sources/Features/Secure Input/SecureInput.swift
  • macos/Sources/Features/Secure Input/SecureInputOverlay.swift
  • macos/Sources/Features/Services/ServiceProvider.swift
  • macos/Sources/Features/Settings/ConfigurationErrorsController.swift
  • macos/Sources/Features/Splits/SplitTree.swift
  • macos/Sources/Features/Splits/SplitView.Divider.swift
  • macos/Sources/Features/Splits/SplitView.swift
  • macos/Sources/Features/Splits/TerminalSplitTreeView.swift
  • macos/Sources/Features/Terminal/BaseTerminalController.swift
  • macos/Sources/Features/Terminal/TerminalController.swift
  • macos/Sources/Features/Terminal/TerminalRestorable.swift
  • macos/Sources/Features/Terminal/TerminalTabColor.swift
  • macos/Sources/Features/Terminal/TerminalView.swift
  • macos/Sources/Features/Terminal/TerminalViewContainer.swift
  • macos/Sources/Features/Terminal/Window Styles/HiddenTitlebarTerminalWindow.swift
  • macos/Sources/Features/Terminal/Window Styles/TerminalWindow.swift
  • macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift
  • macos/Sources/Features/Terminal/Window Styles/TitlebarTabsVenturaTerminalWindow.swift
  • macos/Sources/Features/Terminal/Window Styles/TransparentTitlebarTerminalWindow.swift
  • macos/Sources/Features/Update/UpdateBadge.swift
  • macos/Sources/Features/Update/UpdateController.swift
  • macos/Sources/Features/Update/UpdateDelegate.swift
  • macos/Sources/Features/Update/UpdateDriver.swift
  • macos/Sources/Features/Update/UpdatePill.swift
  • macos/Sources/Features/Update/UpdatePopoverView.swift
  • macos/Sources/Features/Update/UpdateSimulator.swift
  • macos/Sources/Features/Update/UpdateViewModel.swift
  • macos/Sources/Ghostty/FullscreenMode+Extension.swift
  • macos/Sources/Ghostty/Ghostty.Action.swift
  • macos/Sources/Ghostty/Ghostty.App.swift
  • macos/Sources/Ghostty/Ghostty.Config.swift
  • macos/Sources/Ghostty/Ghostty.ConfigTypes.swift
  • macos/Sources/Ghostty/Ghostty.Input.swift
  • macos/Sources/Ghostty/Ghostty.MenuShortcutManager.swift
  • macos/Sources/Ghostty/Ghostty.Surface.swift
  • macos/Sources/Ghostty/GhosttyPackage.swift
  • macos/Sources/Ghostty/GhosttyPackageMeta.swift
  • macos/Sources/Ghostty/NSEvent+Extension.swift
  • macos/Sources/Ghostty/Package.swift
  • macos/Sources/Ghostty/Surface View/InspectorView.swift
  • macos/Sources/Ghostty/Surface View/SurfaceDragSource.swift
  • macos/Sources/Ghostty/Surface View/SurfaceGrabHandle.swift
  • macos/Sources/Ghostty/Surface View/SurfaceProgressBar.swift
  • macos/Sources/Ghostty/Surface View/SurfaceScrollView.swift
  • macos/Sources/Ghostty/Surface View/SurfaceView+Transferable.swift
  • macos/Sources/Ghostty/Surface View/SurfaceView.swift
  • macos/Sources/Ghostty/Surface View/SurfaceView_AppKit.swift
  • macos/Sources/Ghostty/Surface View/SurfaceView_UIKit.swift
  • macos/Sources/Helpers/AnySortKey.swift
  • macos/Sources/Helpers/AppInfo.swift
  • macos/Sources/Helpers/Backport.swift
  • macos/Sources/Helpers/ExpiringUndoManager.swift
  • macos/Sources/Helpers/Extensions/Array+Extension.swift
  • macos/Sources/Helpers/Extensions/EventModifiers+Extension.swift
  • macos/Sources/Helpers/Extensions/NSAppearance+Extension.swift
  • macos/Sources/Helpers/Extensions/NSApplication+Extension.swift
  • macos/Sources/Helpers/Extensions/NSColor+Extension.swift
  • macos/Sources/Helpers/Extensions/NSPasteboard+Extension.swift
  • macos/Sources/Helpers/Extensions/NSScreen+Extension.swift
  • macos/Sources/Helpers/Extensions/NSView+Extension.swift
  • macos/Sources/Helpers/Extensions/NSWindow+Extension.swift
  • macos/Sources/Helpers/Extensions/NSWorkspace+Extension.swift
  • macos/Sources/Helpers/Extensions/OSColor+Extension.swift
  • macos/Sources/Helpers/Extensions/ObjectIdentifier+Extension.swift
  • macos/Sources/Helpers/Extensions/String+Extension.swift
  • macos/Sources/Helpers/Extensions/Transferable+Extension.swift
  • macos/Sources/Helpers/Extensions/UserDefaults+Extension.swift
  • macos/Sources/Helpers/Fullscreen.swift
  • macos/Sources/Helpers/LastWindowPosition.swift
  • macos/Sources/Helpers/MetalView.swift
  • macos/Sources/Helpers/ObjCExceptionCatcher.h
  • macos/Sources/Helpers/ObjCExceptionCatcher.m
  • macos/Sources/Helpers/PermissionRequest.swift
  • macos/Sources/Helpers/TabTitleEditor.swift
  • macos/Tests/ColorizedGhosttyIconTests.swift
  • macos/Tests/Ghostty/ConfigTests.swift
  • macos/Tests/Ghostty/MenuShortcutManagerTests.swift
  • macos/Tests/Ghostty/NormalizedMenuShortcutKeyTests.swift
  • macos/Tests/Ghostty/ShellTests.swift
  • macos/Tests/Helpers/TemporaryConfig.swift
  • macos/Tests/NSPasteboardTests.swift
  • macos/Tests/NSScreenTests.swift
  • macos/Tests/Terminal/TerminalViewContainerTests.swift
  • macos/Tests/Update/ReleaseNotesTests.swift
  • macos/Tests/Update/UpdateStateTests.swift
  • macos/Tests/Update/UpdateViewModelTests.swift
  • macos/build.nu
  • nix/devShell.nix
  • nix/package.nix
  • nix/pkgs/blessed.nix
  • nix/pkgs/ucs-detect.nix
  • nix/pkgs/wcwidth.nix
  • pkg/afl++/LICENSE
  • pkg/afl++/afl.c
  • pkg/afl++/build.zig
  • pkg/afl++/build.zig.zon

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cmux-upstream-sync-0330

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 3000 files

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="CONTRIBUTING.md">

<violation number="1" location="CONTRIBUTING.md:54">
P3: This link points to `.github/VOUCHED.td`, but there is no VOUCHED file in the repo, so readers will hit a broken link. Update it to an existing file or remove the link.</violation>
</file>

<file name="example/c-vt-encode-key/src/main.c">

<violation number="1" location="example/c-vt-encode-key/src/main.c:22">
P3: The example README describes encoding a Ctrl key *release* event, but the code sets the action to `GHOSTTY_KEY_ACTION_PRESS`. Update the action (or the README) so the example matches the documented behavior.</violation>
</file>

<file name="example/c-vt-render/src/main.c">

<violation number="1" location="example/c-vt-render/src/main.c:191">
P1: Ensure the grapheme buffer is at least grapheme_len elements; the fixed 16-element array can overflow when grapheme_len is larger.</violation>
</file>

<file name="example/c-vt-encode-mouse/build.zig.zon">

<violation number="1" location="example/c-vt-encode-mouse/build.zig.zon:2">
P2: Update the package name to match the example directory (and avoid duplicating the existing `c_vt` package name).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.


// Read grapheme codepoints into a buffer and print them.
// The buffer must be at least grapheme_len elements.
uint32_t codepoints[16];
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Mar 30, 2026

Choose a reason for hiding this comment

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

P1: Ensure the grapheme buffer is at least grapheme_len elements; the fixed 16-element array can overflow when grapheme_len is larger.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At example/c-vt-render/src/main.c, line 191:

<comment>Ensure the grapheme buffer is at least grapheme_len elements; the fixed 16-element array can overflow when grapheme_len is larger.</comment>

<file context>
@@ -0,0 +1,234 @@
+
+      // Read grapheme codepoints into a buffer and print them.
+      // The buffer must be at least grapheme_len elements.
+      uint32_t codepoints[16];
+      uint32_t len = grapheme_len < 16 ? grapheme_len : 16;
+      ghostty_render_state_row_cells_get(
</file context>
Fix with Cubic

@@ -0,0 +1,24 @@
.{
.name = .c_vt,
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Mar 30, 2026

Choose a reason for hiding this comment

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

P2: Update the package name to match the example directory (and avoid duplicating the existing c_vt package name).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At example/c-vt-encode-mouse/build.zig.zon, line 2:

<comment>Update the package name to match the example directory (and avoid duplicating the existing `c_vt` package name).</comment>

<file context>
@@ -0,0 +1,24 @@
+.{
+    .name = .c_vt,
+    .version = "0.0.0",
+    .fingerprint = 0x413a8529a6dd3c51,
</file context>
Fix with Cubic

Comment thread CONTRIBUTING.md

If you contributed to Ghostty prior to the introduction
of the vouch system and wish to continue contributing, you were not
automatically added to the [list of vouched users](.github/VOUCHED.td). You will need to follow the same
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Mar 30, 2026

Choose a reason for hiding this comment

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

P3: This link points to .github/VOUCHED.td, but there is no VOUCHED file in the repo, so readers will hit a broken link. Update it to an existing file or remove the link.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At CONTRIBUTING.md, line 54:

<comment>This link points to `.github/VOUCHED.td`, but there is no VOUCHED file in the repo, so readers will hit a broken link. Update it to an existing file or remove the link.</comment>

<file context>
@@ -47,6 +47,13 @@ on a system of trust, and AI has unfortunately made it so we can no
+
+If you contributed to Ghostty prior to the introduction
+of the vouch system and wish to continue contributing, you were not
+automatically added to the [list of vouched users](.github/VOUCHED.td). You will need to follow the same
+process as a first-time contributor to be vouched.
+
</file context>
Suggested change
automatically added to the [list of vouched users](.github/VOUCHED.td). You will need to follow the same
automatically added to the list of vouched users. You will need to follow the same
Fix with Cubic

GhosttyKeyEvent event;
result = ghostty_key_event_new(NULL, &event);
assert(result == GHOSTTY_SUCCESS);
ghostty_key_event_set_action(event, GHOSTTY_KEY_ACTION_PRESS);
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Mar 30, 2026

Choose a reason for hiding this comment

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

P3: The example README describes encoding a Ctrl key release event, but the code sets the action to GHOSTTY_KEY_ACTION_PRESS. Update the action (or the README) so the example matches the documented behavior.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At example/c-vt-encode-key/src/main.c, line 22:

<comment>The example README describes encoding a Ctrl key *release* event, but the code sets the action to `GHOSTTY_KEY_ACTION_PRESS`. Update the action (or the README) so the example matches the documented behavior.</comment>

<file context>
@@ -0,0 +1,40 @@
+  GhosttyKeyEvent event;
+  result = ghostty_key_event_new(NULL, &event);
+  assert(result == GHOSTTY_SUCCESS);
+  ghostty_key_event_set_action(event, GHOSTTY_KEY_ACTION_PRESS);
+  ghostty_key_event_set_key(event, GHOSTTY_KEY_C);
+  ghostty_key_event_set_mods(event, GHOSTTY_MODS_CTRL);
</file context>
Fix with Cubic

Copy link
Copy Markdown

@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: ee2595cae1

ℹ️ 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 +110 to +112
if (!appendPayload(pending, payload_kind, payload_bytes)) {
parser.state = .invalid;
return null;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reset pending OSC 99 state on parse failure

When appendPayload fails, the parser marks the OSC as invalid and returns without clearing parser.kitty_notification_pending. Because this pending buffer is intentionally preserved across OSC sequences, a later fragment with the same i= can be merged with stale title/body data from before the failure, producing an incorrect notification instead of dropping the partial message. Clear the pending notification state on error paths to prevent cross-sequence data contamination.

Useful? React with 👍 / 👎.

);
msg.write_small.len = @intCast(resp.len);
self.messageWriter(msg);
self.sendModeReport(self.terminal.modes.getReport(.{ .value = @truncate(mode_raw), .ansi = ansi }));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve full mode number in unknown DECRPM replies

This truncates mode_raw (u16) into a 15-bit ModeTag value before encoding the response, so unknown mode queries above 32767 are echoed back as a different mode number (e.g. 40000 becomes 7232). That changes protocol-visible behavior for DECRPM unknown-mode replies and can break clients that rely on the returned mode id matching the requested one.

Useful? React with 👍 / 👎.

Upstream restructured the OSC parser, replacing the old `writer` field
and `writeToFixed()` method with the new `capture`/`captureTrailing()`
API. Update the kitty notification parser to use the new capture API.
Copy link
Copy Markdown

@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: f2f7b140d0

ℹ️ 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".


fn requestModeUnknown(self: *Handler, mode_raw: u16, ansi: bool) void {
const report = self.terminal.modes.getReport(.{
.value = @truncate(mode_raw),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve full mode ID in unknown DECRPM replies

Avoid truncating unknown mode queries before encoding the response. In requestModeUnknown, @truncate(mode_raw) narrows a u16 mode number into the 15-bit ModeTag, so queries above 32767 are echoed back as a different mode id (for example, 40000 becomes 7232). That makes protocol-visible DECRPM responses incorrect for clients that correlate replies to the original requested mode.

Useful? React with 👍 / 👎.

@lawrencecchen lawrencecchen force-pushed the cmux-upstream-sync-0330 branch 2 times, most recently from 5268b1f to ce2181d Compare March 30, 2026 23:48
Copy link
Copy Markdown

@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: ce2181d52d

ℹ️ 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 +90 to +94
if (!pending.active or !std.mem.eql(u8, pending.idSlice(), value)) {
pending.reset();
pending.active = true;
pending.id_len = @min(value.len, pending.id.len);
@memcpy(pending.id[0..pending.id_len], value[0..pending.id_len]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve full OSC 99 chunk IDs

The chunk-merging logic truncates i= values to 64 bytes when storing them, but subsequent chunks are compared against the full incoming ID. For any ID longer than 64 bytes, std.mem.eql at the next chunk always fails due to the length mismatch, so the pending title/body state is reset and multipart notifications with long IDs cannot be reassembled correctly. Please either reject oversized IDs up front or store/compare IDs without truncation.

Useful? React with 👍 / 👎.

Upstream removed ghostty_surface_clear_selection and never had
ghostty_surface_select_cursor_cell. Both are needed by cmux for
keyboard copy mode. Re-add implementations.
@lawrencecchen lawrencecchen force-pushed the cmux-upstream-sync-0330 branch from ce2181d to fa0769f Compare March 31, 2026 00:00
Copy link
Copy Markdown

@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: fa0769f3f5

ℹ️ 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 +60 to +61
if (payload_kind == .ignore) {
return null;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Clear partial OSC 99 state when control packets are ignored

Returning immediately for p=close/p=alive leaves kitty_notification_pending untouched, so an in-progress multipart notification (d=0) can survive across those control packets and be incorrectly merged into a later notification that reuses the same i= value. This produces stale title/body concatenation instead of starting a fresh notification, so ignored control packets should reset (or ID-match reset) the pending buffer.

Useful? React with 👍 / 👎.

Swift/Xcode can't import the new SET_TAB_TITLE enum value, causing
all subsequent values to shift by 1. This makes the app misinterpret
actions (e.g. COMMAND_FINISHED matches as START_SEARCH, crashing).

Move set_tab_title to the end of the C ABI Key enum so existing
values keep their positions.
@lawrencecchen lawrencecchen force-pushed the cmux-upstream-sync-0330 branch from d2358b5 to 40c3dcd Compare March 31, 2026 00:33
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.