Bumps
[softprops/action-gh-release](https://github.com/softprops/action-gh-release)
from 3.0.0 to 3.0.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/softprops/action-gh-release/releases">softprops/action-gh-release's
releases</a>.</em></p>
<blockquote>
<h2>v3.0.1</h2>
<h2>3.0.1</h2>
<ul>
<li>maintenance release with updated dependencies</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md">softprops/action-gh-release's
changelog</a>.</em></p>
<blockquote>
<h2>3.0.1</h2>
<ul>
<li>maintenance release with updated dependencies</li>
</ul>
<h2>3.0.0</h2>
<p><code>3.0.0</code> is a major release that moves the action runtime
from Node 20 to Node 24.
Use <code>v3</code> on GitHub-hosted runners and self-hosted fleets that
already support the
Node 24 Actions runtime. If you still need the last Node 20-compatible
line, stay on
<code>v2.6.2</code>.</p>
<h2>What's Changed</h2>
<h3>Other Changes 🔄</h3>
<ul>
<li>Move the action runtime and bundle target to Node 24</li>
<li>Update <code>@types/node</code> to the Node 24 line and allow future
Dependabot updates</li>
<li>Keep the floating major tag on <code>v3</code>; <code>v2</code>
remains pinned to the latest <code>2.x</code> release</li>
</ul>
<h2>2.6.2</h2>
<h2>What's Changed</h2>
<h3>Other Changes 🔄</h3>
<ul>
<li>chore(deps): bump picomatch from 4.0.3 to 4.0.4 by <a
href="https://github.com/dependabot"><code>@dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/775">softprops/action-gh-release#775</a></li>
<li>chore(deps): bump brace-expansion from 5.0.4 to 5.0.5 by <a
href="https://github.com/dependabot"><code>@dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/777">softprops/action-gh-release#777</a></li>
<li>chore(deps): bump vite from 8.0.0 to 8.0.5 by <a
href="https://github.com/dependabot"><code>@dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/781">softprops/action-gh-release#781</a></li>
</ul>
<h2>2.6.1</h2>
<p><code>2.6.1</code> is a patch release focused on restoring linked
discussion thread creation when
<code>discussion_category_name</code> is set. It fixes
<code>[#764](https://github.com/softprops/action-gh-release/issues/764)</code>,
where the draft-first publish flow
stopped carrying the discussion category through the final publish
step.</p>
<p>If you still hit an issue after upgrading, please open a report with
the bug template and include a minimal repro or sanitized workflow
snippet where possible.</p>
<h2>What's Changed</h2>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: preserve discussion category on publish by <a
href="https://github.com/chenrui333"><code>@chenrui333</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/765">softprops/action-gh-release#765</a></li>
</ul>
<h2>2.6.0</h2>
<p><code>2.6.0</code> is a minor release centered on
<code>previous_tag</code> support for
<code>generate_release_notes</code>,
which lets workflows pin GitHub's comparison base explicitly instead of
relying on the default range.
It also includes the recent concurrent asset upload recovery fix, a
<code>working_directory</code> docs sync,
a checked-bundle freshness guard for maintainers, and clearer
immutable-prerelease guidance where
GitHub platform behavior imposes constraints on how prerelease asset
uploads can be published.</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="718ea10b13"><code>718ea10</code></a>
release 3.0.1</li>
<li><a
href="f1a938b9d8"><code>f1a938b</code></a>
chore(deps): bump esbuild from 0.28.0 to 0.28.1 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/802">#802</a>)</li>
<li><a
href="0066ead0de"><code>0066ead</code></a>
chore(deps): bump vite from 8.0.14 to 8.0.16 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/806">#806</a>)</li>
<li><a
href="dc643cac62"><code>dc643ca</code></a>
chore(deps): bump the npm group with 3 updates (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/805">#805</a>)</li>
<li><a
href="85ee99b6b2"><code>85ee99b</code></a>
chore(deps): bump actions/checkout in the github-actions group (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/804">#804</a>)</li>
<li><a
href="9ed3cf9a68"><code>9ed3cf9</code></a>
chore(deps): bump the npm group with 2 updates (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/800">#800</a>)</li>
<li><a
href="3efcac8951"><code>3efcac8</code></a>
chore(deps): bump the npm group with 3 updates (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/798">#798</a>)</li>
<li><a
href="05d6b9164a"><code>05d6b91</code></a>
chore(deps): bump brace-expansion from 5.0.5 to 5.0.6 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/797">#797</a>)</li>
<li><a
href="403a5240f3"><code>403a524</code></a>
chore(deps): bump <code>@types/node</code> from 24.12.2 to 24.12.3 in
the npm group (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/796">#796</a>)</li>
<li><a
href="437e073e78"><code>437e073</code></a>
chore(deps): bump the npm group with 4 updates (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/792">#792</a>)</li>
<li>Additional commits viewable in <a
href="b430933298...718ea10b13">compare
view</a></li>
</ul>
</details>
<br />
[](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>
#12949
I'm unsure about the performance implications of overriding
syncAppearance as opposed to other methods(ie setupKVO or
setupTabGroupObservation) but I found that this shows the tab group
correctly.
## Context
Implements the OSC 133 `click_events=2` such that click events on the
terminal are sent to the shell where the y coordinate is sent relative
to the prompt pin.
See
https://sw.kovidgoyal.net/kitty/shell-integration/#click_events=1|2:~:text=click%5Fevents,xterm
further detailed explanation.
This should close https://github.com/ghostty-org/ghostty/issues/10865
### Testing
I did some basic manual testing here via the following:
```
ghostty main
❯ printf '\033]133;A;click_events=1\007' && cat
^[[<0;49;4M^[[<0;48;8M^[[<0;47;12M^C
ghostty main 5s
❯ printf '\033]133;A;click_events=2\007' && cat
^[[<0;50;1M^[[<0;49;4M^[[<0;48;9M^[[<0;48;14M^C
```
#### Notes
This is my first Ghostty PR. All code here is hand-rolled, AI was used
to do "smart" code searches/point me in the right direction.
I'm actively trying to learn Zig, Ghostty, and get more involved with
the community here so I'm avoiding obtuse usage of AI where possible.
Any feedback or tips are more than welcome! Thank you! 🙏
Previously the libghostty-vt stream handler dropped .report_pwd as a
no-op, so embedders never saw shell-reported cwd changes and the
terminal's pwd field was never populated from escape sequences.
Wire the action to setPwd and expose a pwd_changed callback analogous to
title_changed via GHOSTTY_TERMINAL_OPT_PWD_CHANGED. The payload is
passed through unparsed; embedders read it with ghostty_terminal_get and
decode any URI scheme themselves.
This is proposed in
[discussion#12927](https://github.com/ghostty-org/ghostty/discussions/12927)
Previously the libghostty-vt stream handler dropped .report_pwd as a
no-op, so embedders never saw shell-reported cwd changes and the
terminal's pwd field was never populated from escape sequences.
Wire the action to setPwd and expose a pwd_changed callback analogous
to title_changed via GHOSTTY_TERMINAL_OPT_PWD_CHANGED. The payload is
passed through unparsed; embedders read it with ghostty_terminal_get
and decode any URI scheme themselves.
## Summary
- Adds a "Close Split" option to the right-click context menu in the
split submenu
- Allows users to close the focused split pane directly from the context
menu
Reference discussion:
https://github.com/ghostty-org/ghostty/discussions/10982
This hooks up the glyph protocol glossary to the terminal state. This
effectively makes us handle the APC protocol for it both in Ghostty GUI
and libghostty, although we didn't implement the renderer yet.
The Zig/C libghostty API also has a way to disable the protocol but it
is enabled by default. The memory usage is bound by the specification.
For dirty tracking for the renderer, we're going with the simple route
that any glyph change marks a coarse grained dirty flag and we'll [in
the future] rebuild the entire state in the renderer. I think this will
be fine for realistic workloads, but we can reassess in the future when
we have real workloads.
This hooks up the glyph protocol glossary to the terminal state. This
effectively makes us handle the APC protocol for it both in Ghostty GUI
and libghostty, although we didn't implement the renderer yet.
The Zig/C libghostty API also has a way to disable the protocol but it is
enabled by default. The memory usage is bound by the specification.
For dirty tracking for the renderer, we're going with the simple route that
any glyph change marks a coarse grained dirty flag and we'll [in the future]
rebuild the entire state in the renderer. I think this will be fine for
realistic workloads, but we can reassess in the future when we have
real workloads.
Also found when test searching.
Run Ghostty debug on macOS and follow these steps:
1. Open Ghostty, `cat src/Surface.zig` and start search
`self.startClipboardRequest`.
2. Click up button(Press enter) 6 times and click down button (Press
shift+enter) 6 times.
3. You should see a panic crash.
### AI Disclosure
Claude implemented the fix and the unit test.
I reviewed it and tested it myself.
selectPrev's wrap (active_len + history_len - 1) would underflow if a
selection were live while both result lists are empty. Add a test that
exercises the invariant making that unreachable: overwriting the only match
forces a reload that empties both lists and drops the selection, so the next
select() hits the no-matches guard instead of the wrap arithmetic.
Found this issue when testing some search features; follow up for
#12907.
You can either reproduce using the PoC below with `libghostty-vt` or run
Ghostty debug on macOS and follow these steps:
1. Open Ghostty and start search `0`.
2. Press `cmd+=` to increase font size.
3. You should see a panic crash.
### AI Disclosure
As the commit suggests, Claude implemented the fix, the unit test, and
PoC file.
I reviewed it(seems reasonable to me, but I’m not a Zig professional)
and tested it myself.
```zig
// PoC: resize panic when shrinking both axes with the cursor near the top
// of a fully-populated screen.
//
// Build (with libghostty-vt headers + dylib on the standard search paths):
// zig run poc.zig -lghostty-vt
//
// Or point at a local build:
// zig run poc.zig -I <prefix>/include -L <prefix>/lib -lghostty-vt
//
// At runtime the dylib must be discoverable (DYLD_LIBRARY_PATH on macOS,
// LD_LIBRARY_PATH on Linux, or an rpath baked in at link time).
//
// Without the fix, this aborts with
// reached unreachable code (assert in PageList.Pin.pageIterator)
// at _terminal.PageList.resizeCols on a debug/safe build. On release it
// silently iterates an empty (reversed) range.
const std = @import("std");
const c = @cImport({
@cInclude("ghostty/vt.h");
});
pub fn main() !void {
var term: c.GhosttyTerminal = null;
const opts: c.GhosttyTerminalOptions = .{
.cols = 80,
.rows = 24,
.max_scrollback = 1000,
};
if (c.ghostty_terminal_new(null, &term, opts) != c.GHOSTTY_SUCCESS) {
return error.InitFailed;
}
defer c.ghostty_terminal_free(term);
// Fill every one of the 24 active rows with non-blank content. This is
// what makes the bug reachable: when rows shrink, resizeWithoutReflow
// can only trim *blank* trailing rows, so non-blank rows are instead
// pushed up into scrollback and the active-area top moves down.
{
var buf: [256]u8 = undefined;
var i: usize = 0;
while (i < 24) : (i += 1) {
// "X" on each row; CR+LF between rows but not after the last so
// we don't scroll the top row away.
const line = if (i + 1 < 24)
std.fmt.bufPrint(&buf, "X\r\n", .{}) catch unreachable
else
std.fmt.bufPrint(&buf, "X", .{}) catch unreachable;
c.ghostty_terminal_vt_write(term, line.ptr, line.len);
}
}
// CSI 1;1H -> park the cursor on the TOP row (1-based). The active area is
// anchored to the bottom, so once we shrink rows this row falls above the
// new active-area top, i.e. into scrollback.
const move = "\x1b[1;1H";
c.ghostty_terminal_vt_write(term, move.ptr, move.len);
// Shrink both axes. Columns must shrink to take resize()'s .lt branch,
// which runs the row shrink first and then resizeCols with the original
// (now out-of-active-area) cursor pin. Panics in
// _terminal.PageList.resizeCols.
_ = c.ghostty_terminal_resize(term, 79, 20, 8, 16);
std.debug.print("survived resize (fix is present)\n", .{});
}
```
This adds the glossary and request handler logic to the glyph protocol
package.
We now have a fully spec compliant business-logic part of the glyph
protocol.
**This doesn't yet hook it up to terminal state.** So it isn't impacting
any real-world usage yet.
Code was hand-written, tests were AI-assisted and human reviewed.
Extend glyph render constraints with cell-span sizing modes for height,
width, contain, cover bounds, and stretch bounds. These preserve the
existing face-targeted behavior for platform fonts, emoji, and Nerd Font
rules while giving registered glyphs a target based on terminal cell
spans.
Map Glyph Protocol registration options to the new constraint modes so
sizing follows the spec formulas based on authored advance width and line
height. Baseline alignment now places design-space y=0 on the terminal
text baseline instead of approximating it as start alignment.
Document the placement formulas in the local protocol summary and add
focused tests for constraint mapping, cell-span padding, line-height and
advance scaling, contain versus cover behavior, stretch, and baseline
placement.
Register parsing now validates the full register request shape before
constructing the parsed command. Inputs that only contain the verb
separator, such as `r`, `r;cp=e0a0`, or `r;foo`, now fail with
InvalidFormat instead of reaching Register invariants guarded by asserts.
Valid empty-payload requests still parse when they include the payload
separator, allowing execution to report malformed_payload through the
normal protocol response path.
Glyph clear execution previously treated an unparsable cp option the same
as an omitted cp option. That made inputs such as c;cp=zz behave like a
bare clear request and remove every glossary registration.
Track clear option presence separately from successful decoding. A
present but malformed cp now returns a malformed_payload clear failure
without mutating the glossary, while an omitted cp still clears all
registrations.
In the column-shrink (.lt) branch of PageList.resize, resizeWithoutReflow
lowers self.rows before resizeCols runs. Because the active area is anchored
to the bottom, shrinking rows moves the active-area top down; a cursor near
the top of the old active area then ends up above the new active area (in
scrollback).
resizeCols counts wrap continuations from the cursor pin up to the active-area
top via a .left_up rowIterator. When the cursor pin is above the limit, the
range is reversed and the iterator's order assertion fires (SIGABRT in debug;
silently iterates empty in release).
Count zero wraps when the cursor pin is above the active area, mirroring the
post-reflow preserved-cursor block which already no-ops for a non-active
cursor. Add a regression test.