Closes#7877.
Small disclaimer: First Ghostty PR and Zig PR, but looking forward to
contributing to the project.
This PR supports shell-integration-features `ssh-env` and `ssh-terminfo`
as per other shells, but not the rest as this is what the issue states.
That being said, with this PR, then you would see this:
- `warning(io_exec): shell could not be detected, no automatic shell
integration will be injected`, but given that the default mode is
`detect` it will pick up the executable and if ssh features are enabled
it will integrate it. This might be confusing for users.
- I decided to not add `nu` to `pub const Shell` because if we do so,
then from what I understand from the code, then the code flow would
imply that "shell integration will be injected" but it will only do so
if those `ssh-*` features are enabled, which may be misleading. But on
the other hand, providing `ssh` shell integration but returning `null`
for `?!ShellIntegration` does not seem very correct either.
- I dont like that I added `features` argument to `setupshell`, just to
check them if `nu` was used. The reasoning is because the way Nushell
works, if we autoload the `nushell` directory (by `setupXdgDatadirs()`)
even if no `ssh` features were present, it will wrap the `ssh` function
and I think that is not desirable, even if we end up just forwarding the
arguments.
Sorry for the long wall of text, but I think it was worth to add some of
the doubts I have had myself, plus the ones that you folks may add. I am
very happy to iterate on this, even if its a very "Easy" one, so I much
welcome the feedback.
> [!NOTE]
>
> Used `GPT` for helping with nushell variable naming
verification/improvement
> Used `Gemini` for helping with understanding the `Zsh` ssh integration
so that I could replicate the logic with nushell. Just because I find
`zsh` language very difficult to understand in detail.
Bumps
[hustcer/milestone-action](https://github.com/hustcer/milestone-action)
from 3.0 to 3.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/hustcer/milestone-action/releases">hustcer/milestone-action's
releases</a>.</em></p>
<blockquote>
<h2>v3.1</h2>
<h2>[3.1] - 2026-01-23</h2>
<h3>Documentation</h3>
<ul>
<li>Update milestone-action version in README (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/162">#162</a>)</li>
</ul>
<h3>Features</h3>
<ul>
<li>Break before sleep when milestone found</li>
</ul>
<h3>Miscellaneous Tasks</h3>
<ul>
<li>Update README.md (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/166">#166</a>)</li>
</ul>
<h3>Deps</h3>
<ul>
<li>Update Nu to 0.109.1</li>
<li>Update Nushell to 0.110.0 (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/167">#167</a>)</li>
<li>Upgrade hustcer/setup-nu to v3.22</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/hustcer/milestone-action/blob/main/CHANGELOG.md">hustcer/milestone-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<h2>[3.1] - 2026-01-23</h2>
<h3>Documentation</h3>
<ul>
<li>Update milestone-action version in README (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/162">#162</a>)</li>
</ul>
<h3>Features</h3>
<ul>
<li>Break before sleep when milestone found</li>
</ul>
<h3>Miscellaneous Tasks</h3>
<ul>
<li>Update README.md (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/166">#166</a>)</li>
</ul>
<h3>Deps</h3>
<ul>
<li>Update Nu to 0.109.1</li>
<li>Update Nushell to 0.110.0 (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/167">#167</a>)</li>
<li>Upgrade hustcer/setup-nu to v3.22</li>
</ul>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<h2>[3.0] - 2025-10-26</h2>
<p>This release introduces changes that may impact some users. If the
action fails due to insufficient permissions, please add the
<code>issues: write</code> and <code>pull-requests: write</code>
permissions to your workflow. Additionally, the API for binding
milestones has been modified. Due to these changes, the major version
has been incremented to 3.</p>
<h3>Bug Fixes</h3>
<ul>
<li>Try to fix GitHub Projects (classic) deprecation warning by using
REST API instead of GraphQL (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/157">#157</a>)</li>
<li>Fix "Resource not accessible by integration" error for
issue milestone binding by adding <code>issues: write</code>
permission</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Update README with required permissions configuration</li>
<li>Remove unnecessary <code>contents: write</code> permission
requirement</li>
</ul>
<h2>[2.12] - 2025-10-25</h2>
<h3>Bug Fixes</h3>
<ul>
<li>Fix some typos</li>
</ul>
<h3>Miscellaneous Tasks</h3>
<ul>
<li>Sort milestones by due date, then creation time (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/153">#153</a>)</li>
<li>Update output table width for logs</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="ebed8d5daa"><code>ebed8d5</code></a>
Bump to v3.1</li>
<li><a
href="e2f911c127"><code>e2f911c</code></a>
chore: Update Nushell to 0.110.0 (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/167">#167</a>)</li>
<li><a
href="800adcbc5e"><code>800adcb</code></a>
deps: Upgrade hustcer/setup-nu to v3.22</li>
<li><a
href="91ff3608b5"><code>91ff360</code></a>
deps: Update Nu to 0.109.1</li>
<li><a
href="906178b9f5"><code>906178b</code></a>
chore: Update README.md (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/166">#166</a>)</li>
<li><a
href="90f06528b6"><code>90f0652</code></a>
feat: Break before sleep when milestone found</li>
<li><a
href="93d96c3f77"><code>93d96c3</code></a>
Update CHANGELOG.md</li>
<li><a
href="7ee8118a50"><code>7ee8118</code></a>
docs: Update milestone-action version in README (<a
href="https://redirect.github.com/hustcer/milestone-action/issues/162">#162</a>)</li>
<li><a
href="8d333973bd"><code>8d33397</code></a>
Try to remove permission section</li>
<li>See full diff in <a
href="dcd6c3742a...ebed8d5daa">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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
Bumps [cachix/cachix-action](https://github.com/cachix/cachix-action)
from 0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad to
3ba601ff5bbb07c7220846facfa2cd81eeee15a1.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3ba601ff5b"><code>3ba601f</code></a>
deps: bump devenv</li>
<li><a
href="74ef2c6e52"><code>74ef2c6</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/cachix-action/issues/209">#209</a>
from cachix/socket-fallback</li>
<li><a
href="005ab3fd5b"><code>005ab3f</code></a>
daemon: fall back to os.tmpdir if the socket path is too long</li>
<li><a
href="29121a2db1"><code>29121a2</code></a>
ci: migrate from macos-13 to macos-15-intel</li>
<li><a
href="ee79db531b"><code>ee79db5</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/cachix-action/issues/207">#207</a>
from cachix/dependabot/github_actions/actions/checkout-5</li>
<li><a
href="88d030f69b"><code>88d030f</code></a>
chore(deps): bump actions/checkout from 4 to 5</li>
<li><a
href="1d49a1c200"><code>1d49a1c</code></a>
docs: update badge</li>
<li><a
href="a7ae943f0b"><code>a7ae943</code></a>
dev: enable shellcheck and lint</li>
<li><a
href="3e77af4f23"><code>3e77af4</code></a>
docs: expand dev docs</li>
<li><a
href="d28f02e1e2"><code>d28f02e</code></a>
docs: update more descriptions</li>
<li>Additional commits viewable in <a
href="0fc020193b...3ba601ff5b">compare
view</a></li>
</ul>
</details>
<br />
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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
This changes our OSC133 parser to parse options lazily. We do this for
multiple reasons:
1. Parsing all our options ahead of time balloons our required
osc.Command tagged union type which has C ABI implications. Adding all
supported options (including Kitty extensions) today already breaks our
C ABI.
2. Invalid options are allowed by the specification and should be
explicitly ignored, so we don't need to validate options at all during
parse time.
3. Semantic prompt markers don't need to be high throughput, so we can
afford to do some extra work at processing time to gather the options.
They're also rather short usually.
cc @jparise
This changes our OSC133 parser to parse options lazily. We do this for
multiple reasons:
1. Parsing all our options ahead of time balloons our required
osc.Command tagged union type which has C ABI implications. Adding
all supported options (including Kitty extensions) today already
breaks our C ABI.
2. Invalid options are allowed by the specification and should be
explicitly ignored, so we don't need to validate options at all
during parse time.
3. Semantic prompt markers don't need to be high throughput, so we
can afford to do some extra work at processing time to gather
the options. They're also rather short usually.
Related to #5932
This updates our OSC parser to parse the full OSC 133 specification:
https://gitlab.freedesktop.org/Per_Bothner/specifications/blob/master/proposals/semantic-prompts.md
The logic for handling these events was _unchanged_ from our prior
implementation. This is just a parser-only update. As such, we ignore a
bunch of semantic prompt command we should definitely handle, and
incorrectly handle others. This is the crux of #5932 that I want to head
towards fixing. This PR just contains the parser updates.
I also retained all the Kitty parser extensions.
**AI disclosure:** AI helped a lot of the rote tasks once I manually did
a few. I'm still reviewing this manually but will do so shortly.
Follow up to #8289
The rise of agentic programming has eliminated the natural effort-based
backpressure that previously limited low-effort contributions. It is now
too easy to create large amounts of bad content with minimal effort.
Open source projects have always had poor quality issues, PRs, etc. That
comes with the territory. Unfortunately, the ease and carelessness by
which these are now manifested has increased the "bad" count by 10x if
not more. It's ruining it for the rest of us. This policy is a result of
the bad, and I'm sorry about it.
**Going forward, AI generated contributions will only be allowed for
accepted issues and maintainers.** Drive-by pull requests with AI
generated content will be immediately closed.
**Going further, users who contribute bad AI generated content will be
immediately banned from all future contributions.** This is a
zero-tolerance policy. If you use AI, you are responsible for the
quality of your contributions. If you're using low-effort AI to create
low-effort content, I have no human obligation to help you.
If you are a junior developer who is really trying to learn and get
better, then please put aside the AI, do your best, and I will still
help. I want to help. But I expect effort and organic thinking in
return.
> [!IMPORTANT]
>
> This is not an anti-AI stance. This is an anti-idiot stance. Ghostty
is written with plenty of AI assistance and many of our maintainers use
AI daily. We just want quality contributions, regardless of how they are
made.
Follow up to #8289
The rise of agentic programming has eliminated the natural effort-based
backpressure that previously limited low-effort contributions. It is
now too easy to create large amounts of bad content with minimal effort.
Open source projects have always had poor quality issues, PRs, etc. That
comes with the territory. Unfortunately, the ease and carelessness by which
these are now manifested has increased the "bad" count by 10x if not more.
It's ruining it for the rest of us. This policy is a result of the bad, and
I'm sorry about it.
**Going forward, AI generated contributions will only be allowed for
accepted issues and maintainers.** Drive-by pull requests with AI generated
content will be immediately closed.
**Going further, users who contribute bad AI generated content will be
immediately banned from all future contributions.** This is a zero-tolerance
policy. If you use AI, you are responsible for the quality of your
contributions. If you're using low-effort AI to create low-effort content,
I have no human obligation to help you.
If you are a junior developer who is really trying to learn and get
better, then please put aside the AI, do your best, and I will still
help. I want to help. But I expect effort and organic thinking in return.
This is not an anti-AI stance. This is an anti-idiot stance. Ghostty is
written with plenty of AI assistance and many of our maintainers use
AI daily. We just want quality contributions, regardless of how they are
made.
Refer to discussion #10000
When a tab contains only a single split, resize_split and
toggle_split_zoom actions now return false (not performed). This allows
keybindings marked with `performable: true` to pass the event through to
the terminal program.
The performable flag causes unperformed actions to be treated as if the
binding didn't exist, so the key event is sent to the terminal instead
of being consumed.
- Add isSplit() helper to SplitTree to detect single-pane vs split state
- Update GTK resizeSplit/toggleSplitZoom to return false when single
pane
- Update macOS resizeSplit/toggleSplitZoom to return Bool and check
isSplit
- Add unit test for isSplit method
Currently, if a user clicks the "xmark" button to close the search box,
the main interface does not regain focus until clicked again. This patch
focuses the surface view upon closing.
This adds a new single-file library called "Tripwire" in
`src/tripwire.zig`. This library helps inject failures around `try`
cases for the purpose of testing `errdefer`. It is fully optimized away
in non-test builds (even debug), turning into zero space and zero
assembly.
From this, I've verified (via unit tests w/ tripwire) and fixed a number
of errdefer issues:
* PageList init with non-standard pages that requires more than 1 page
can leak on allocation error on the 2nd+ loop
* Tabstop allocation failure on resize corrupts the internal state
(invalid cols)
* `Screen.selectionString` would leak memory on late allocation failures
* Screen search could leak memory on late allocation failures
* `SharedGrid.renderGlyph` in our font subsystem would corrupt the glyph
cache if failure occurred
* `SharedGrid.init` could leak memory if loading font metrics failed
In addition to the bugs found, there is now tripwire coverage around
more of our core and we should continue to add more. I've also added
significantly more explicit error sets as I found them.
**AI disclosure:** AI wrote some of the tests, but tripwire itself is
all handwritten and everything was reviewed.
Add errdefer cleanup for codepoints and glyphs hash maps in init().
Previously, if ensureTotalCapacity or reloadMetrics() failed after
allocating these maps, they would leak.
Add tripwire test to verify all failure points in init().
Add errdefer to remove cache entry after getOrPut if subsequent
operations fail (getPresentation, atlas.grow, renderGlyph). Without
this, failed renders would leave uninitialized/garbage entries in
the glyph cache, potentially causing crashes or incorrect rendering.
Add tripwire test to verify the rollback behavior.