Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
37c86b8
Port Ghostty VT 1.4 source and build recipe for qualification
jamesyong-42 Oct 29, 2026
e0a650f
Keep Zig 0.17 packages in writable build output
jamesyong-42 Oct 29, 2026
8667f1d
ci(ghostty): select native pkg-config for Windows candidate builds
jamesyong-42 Oct 29, 2026
761a9eb
fix(ghostty): preserve terminal geometry and verify candidate runtimes
jamesyong-42 Oct 29, 2026
263df6a
test(ffi): recognize upstream Windows and FreeBSD reclamation
jamesyong-42 Oct 29, 2026
0abf8ef
fix(text): respect host emoji cell boundaries
jamesyong-42 Oct 29, 2026
e3ebe35
fix(text): fit joined emoji to their visual cell span
jamesyong-42 Oct 29, 2026
00be88b
build(vt): pin verified ghostty 1.4 candidate artifacts
jamesyong-42 Oct 29, 2026
a2be35c
feat(terminal): copy selections from routed hosts
jamesyong-42 Oct 29, 2026
adf5ae0
fix(build): normalize Darwin runtime symbols in cross-builds
jamesyong-42 Oct 29, 2026
fafd72e
fix(render): follow host cell widths for selections and graphics
jamesyong-42 Oct 29, 2026
aff22c6
build(vt): pin normalized and consumer-tested 1.4 artifacts
jamesyong-42 Oct 29, 2026
e30a1c2
fix(build): read cargo outputs from their configured directory
jamesyong-42 Oct 30, 2026
43f90b9
test(terminal): record migration qualification and reviewed font pixels
jamesyong-42 Oct 30, 2026
d7b5f15
docs(terminal): record final iPhone tests and network gate
jamesyong-42 Oct 30, 2026
cf7cbb4
docs(qualification): record final device and desktop results
jamesyong-42 Oct 30, 2026
5956682
docs: record Ghostty 1.4 regression history and resolutions
jamesyong-42 Nov 1, 2026
59c002f
fix(apple): preserve remote font scaling and seamless block graphics
jamesyong-42 Nov 3, 2026
ce80daa
fix(react): restore routed input safely after visibility changes
jamesyong-42 Nov 3, 2026
40376eb
release: prepare Ghosttea 0.14.0 on Ghostty 1.4
jamesyong-42 Nov 3, 2026
50e5c39
release: pin 0.14.0 Apple native artifact
github-actions[bot] Nov 3, 2026
3901da0
docs: record committed migration fixes and 0.14 release qualification
jamesyong-42 Nov 3, 2026
a53a167
ci: run the desktop gate on the pinned Xcode 26.6 image
jamesyong-42 Nov 3, 2026
dbd7683
docs: track the Truffle DNS release prerequisite
jamesyong-42 Nov 3, 2026
7a1de38
fix(apple): pin verified Truffle 0.7.26 DNS metadata release
jamesyong-42 Nov 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/desktop-release-gates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ concurrency:

jobs:
verify:
runs-on: macos-15
# The Ghostty 1.4 recipe pins Xcode 26.6, which the macOS 15 image lacks.
runs-on: macos-26
timeout-minutes: 45
env:
GHOSTTY_DEVELOPER_DIR: /Applications/Xcode_26.3.app/Contents/Developer
DEVELOPER_DIR: /Applications/Xcode_26.6.app/Contents/Developer
GHOSTTY_DEVELOPER_DIR: /Applications/Xcode_26.6.app/Contents/Developer
GHOSTTEA_SOAK_SESSIONS: ${{ github.event_name == 'schedule' && '1024' || '256' }}
GHOSTTEA_SOAK_ROUNDS: ${{ github.event_name == 'schedule' && '4' || '1' }}
steps:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/ghosttea-apple-native-artifact.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ on:
- "native/ghostty.lock.json"
- "native/ssh.lock.json"
- "scripts/build-ghosttea-apple-native.mjs"
- "scripts/cargo-target-directory.mjs"
- "scripts/build-ghostty-vt-apple.mjs"
- "scripts/ghostty-vt-target.mjs"
- "scripts/build-ssh-candidate-apple.mjs"
Expand Down Expand Up @@ -108,7 +109,7 @@ jobs:
timeout-minutes: 90
env:
DEVELOPER_DIR: /Applications/Xcode_26.6.app/Contents/Developer
GHOSTTY_DEVELOPER_DIR: /Applications/Xcode_26.3.app/Contents/Developer
GHOSTTY_DEVELOPER_DIR: /Applications/Xcode_26.6.app/Contents/Developer
permissions:
attestations: write
contents: read
Expand Down
60 changes: 60 additions & 0 deletions .github/workflows/ghostty-vt-artifact.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,23 @@ jobs:
if: github.ref_type != 'tag'
run: npm run package:ghostty-vt -- --target=aarch64-apple-darwin --allow-mismatch

- if: github.ref_type != 'tag'
uses: dtolnay/rust-toolchain@1.99.1

- name: Test consumers of the normalized macOS archive
if: github.ref_type != 'tag'
env:
GHOSTTY_DEVELOPER_DIR: /Applications/Xcode_26.6.app/Contents/Developer
RUSTFLAGS: -Dlinker-messages
run: |
npm run bootstrap:ghostty-vt:apple
npm run sync:fonts
export GHOSTTY_VT_PREFIX="$PWD/native/build/ghostty/aarch64-apple-darwin/install"
export GHOSTTEA_GHOSTTY_VT_OFFLINE=1
export GHOSTTEA_FONT_DIR="$PWD/native/build/ghosttea-fonts"
cargo test --locked -p ghosttea-vt -p ghosttea-text -p ghosttea-core -p ghosttea-ffi
cargo test --locked -p ghosttea-ffi --test parity -- --ignored

- name: Resolve locked macOS candidate run
if: github.ref_type == 'tag'
id: macos_candidate
Expand Down Expand Up @@ -174,13 +191,56 @@ jobs:

- run: npm ci --ignore-scripts

# Zig 0.17 queries Windows system libraries through pkg-config. The
# runner's Strawberry Perl .BAT shim fails when spawned by Zig; use a
# native executable and record the tool version in the build recipe.
- name: Select native pkg-config
if: github.ref_type != 'tag'
shell: pwsh
run: |
$recipe = (Get-Content native/ghostty.lock.json | ConvertFrom-Json).builder.windowsPkgConfig
for ($attempt = 1; $attempt -le 3; $attempt++) {
choco install $recipe.package --version=$($recipe.version) --yes --no-progress
if ($LASTEXITCODE -eq 0) { break }
if ($attempt -eq 3) { throw "pkg-config installation failed" }
Start-Sleep -Seconds 10
}
$exe = Get-ChildItem "$env:ChocolateyInstall/lib/$($recipe.package)" -Recurse -Filter pkg-config.exe | Select-Object -First 1
if (-not $exe) { throw "native pkg-config executable was not installed" }
& $exe.FullName --version
if ($LASTEXITCODE -ne 0) { throw "native pkg-config is not executable" }
"PKG_CONFIG=$($exe.FullName)" >> $env:GITHUB_ENV

- name: Build native Windows candidate
if: github.ref_type != 'tag'
run: |
npm run bootstrap:ghostty-vt -- --target="$TARGET"
npm run build:ghostty-vt -- --target="$TARGET"
npm run package:ghostty-vt -- --target="$TARGET" --allow-mismatch

- name: Test Rust consumers with the selected Windows runtime
if: github.ref_type != 'tag'
timeout-minutes: 20
run: |
export GHOSTTY_VT_PREFIX="$(cygpath -w "$PWD/native/build/ghostty/$TARGET/install")"
export GHOSTTEA_GHOSTTY_VT_OFFLINE=1
export GHOSTTEA_FONT_DIR="$(cygpath -w "$PWD/native/build/ghosttea-fonts")"
if [ "$TARGET" = "x86_64-pc-windows-msvc-crt-static" ]; then
export RUSTFLAGS="-C target-feature=+crt-static"
fi
node scripts/sync-ghosttea-fonts.mjs
cargo test --locked --target x86_64-pc-windows-msvc -p ghosttea-vt -p ghosttea-text -p ghosttea-core -p ghosttea-ffi
cargo test --locked --target x86_64-pc-windows-msvc -p ghosttea-ffi --test parity -- --ignored

- name: Preserve rejected Windows build for diagnosis
if: failure() && github.ref_type != 'tag'
uses: actions/upload-artifact@v7
with:
name: rejected-${{ matrix.target }}
path: native/build/ghostty/${{ matrix.target }}/install/
retention-days: 7
if-no-files-found: ignore

- name: Resolve locked Windows candidate run
if: github.ref_type == 'tag'
id: windows_candidate
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ios-release-hardening.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
timeout-minutes: 90
env:
DEVELOPER_DIR: /Applications/Xcode_26.6.app/Contents/Developer
GHOSTTY_DEVELOPER_DIR: /Applications/Xcode_26.3.app/Contents/Developer
GHOSTTY_DEVELOPER_DIR: /Applications/Xcode_26.6.app/Contents/Developer
steps:
- uses: actions/checkout@v7

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ jobs:
timeout-minutes: 75
env:
DEVELOPER_DIR: /Applications/Xcode_26.6.app/Contents/Developer
GHOSTTY_DEVELOPER_DIR: /Applications/Xcode_26.3.app/Contents/Developer
GHOSTTY_DEVELOPER_DIR: /Applications/Xcode_26.6.app/Contents/Developer
RELEASE_TAG: ${{ needs.resolve.outputs.release_tag }}
steps:
- uses: actions/checkout@v7
Expand Down Expand Up @@ -281,7 +281,7 @@ jobs:
timeout-minutes: 75
env:
DEVELOPER_DIR: /Applications/Xcode_26.6.app/Contents/Developer
GHOSTTY_DEVELOPER_DIR: /Applications/Xcode_26.3.app/Contents/Developer
GHOSTTY_DEVELOPER_DIR: /Applications/Xcode_26.6.app/Contents/Developer
RELEASE_TAG: ${{ needs.resolve.outputs.release_tag }}
steps:
- uses: actions/checkout@v7
Expand Down
39 changes: 39 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,45 @@
All notable changes to Ghosttea are documented here. The Rust and npm packages
share one version.

## 0.14.0 - 2026-11-02

### Changed

- Upgrade the terminal engine to Ghostty 1.4 at
`83fb95624b0439ee660c2679b43b38c8b63769cd`, with Unicode 18 cell widths and
the checksum-locked Zig 0.17 build recipe. The native build and Apple renderer
retain Ghosttea's host-owned terminal geometry and embedding patches.
- Rebuild the Apple native artifact from the release sources. Windows keeps
separate dynamic-CRT and static-CRT VT archives; macOS archives apply the
pinned upstream Darwin runtime-symbol normalization before packaging.

### Added

- Routed terminal selection copy through the optional `selection-text`
capability. Copy uses read authority, supports Unicode and scrollback, and
rejects stale, oversized or timed-out results without replaying requests.
- Apple remote viewers can declare the source frame's text metrics, so changing
the viewer's font size scales incoming glyphs with its terminal grid.

### Fixed

- Foreground routed panes recover after background retry exhaustion. Input
remains gated until resumed demand is accepted and a fresh cell status arrives.
- Solid block and quadrant characters fill their cells in the Apple renderer,
removing horizontal gaps in TUI artwork at different font sizes and display
scales. Selection, cursor colors and faint opacity remain consistent.
- Joined emoji follow host cell boundaries while keeping their intended visual
span. Selection backgrounds cover the host's complete glyph spans, and graphics
classification preserves host glyphs when Unicode widths are ambiguous.
- Native packaging locates Cargo outputs through the configured target directory.

### Qualification

- Migration evidence and remaining limits are recorded in
`docs/ghostty-1.4-migration.md` and `docs/ghostty-1.4-qualification/`.
Latency remains unqualified; physical Windows GPU and real Wi-Fi/cellular
handoff are not claimed. Release CI verifies the final published artifacts.

## 0.13.8 - 2026-11-02

### Fixed
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Seven Rust crates, ten `@vibecook/*` npm packages and the SwiftPM package share
- Rust 1.88+, the workspace minimum. There is no rust-toolchain file.
- Apple work also needs:
- Xcode 26.6.
- Xcode 26.3 installed side by side at `/Applications/Xcode_26.3.app`. It is used only for the Ghostty/Zig 0.15.2 build; override the path with `GHOSTTY_DEVELOPER_DIR`.
- Ghostty 1.4 uses the locked Zig 0.17.0 and Xcode 26.6 toolchain; `GHOSTTY_DEVELOPER_DIR` can select that Xcode installation.
- Rust 1.97.1 with the `aarch64-apple-ios` and `aarch64-apple-ios-sim` targets.

**Get started**
Expand All @@ -36,7 +36,7 @@ npm run dev # build:sdk, then the Electron demo (apps/desktop, workspace "ghos
2. `test:desktop`: vitest in every workspace, `cargo test --workspace --locked`, the FFI parity/ASan probe, the release-script tests, the integration smokes and the bench tests.
3. `package:check:built`: packs every package and crate, then builds consumers from those archives.
4. `test:lifecycle:soak`.
- **Before running locally:** run `npm run bootstrap:ghostty-vt` once before `ci:desktop` or `test:desktop`. `test:ghosttea-core:ffi` syncs fonts from `native/vendor/ghostty` at the locked commit and fails without it. CI on macOS uses the `:apple` variant, which needs Xcode 26.3.
- **Before running locally:** run `npm run bootstrap:ghostty-vt` once before `ci:desktop` or `test:desktop`. `test:ghosttea-core:ffi` syncs fonts from `native/vendor/ghostty` at the locked commit and fails without it. CI on macOS uses the `:apple` variant, which uses the locked Xcode 26.6 toolchain.
- **Format and lint:** `npm run format` writes prettier and `cargo fmt`. `npm run lint` runs eslint with `--max-warnings 0`. Prettier (width 120, LF line endings enforced by `.gitattributes`) covers only the paths named in the `format` script, not `docs/`, `draft/`, `apple/` or `native/`.
- **Full checks:** `npm run check` runs the lint and type checks plus the iOS release-metadata gates: BOM, resources, App Store, beta matrix and SwiftPM manifests.

Expand Down
24 changes: 12 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ members = [
]

[workspace.package]
version = "0.13.8"
version = "0.14.0"
edition = "2024"
rust-version = "1.88"
authors = ["James Yong"]
Expand Down
10 changes: 5 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
import PackageDescription

let appleNativeURL =
"https://github.com/vibecook-dev/ghosttea/releases/download/ghosttea-apple-native-be8c80c9cfd3/GhostteaAppleNative.xcframework.zip"
let appleNativeChecksum = "2a9e41d98e7e746c61cc0a4c61d6505cee5b69977ff4796db6f4de93a51362f9"
"https://github.com/vibecook-dev/ghosttea/releases/download/ghosttea-apple-native-fcf9a17cce90/GhostteaAppleNative.xcframework.zip"
let appleNativeChecksum = "5a4a72b9aeb5d11a05170e2f423327f9cd3405d7eaf64f7d3e01467e68ec896c"

// Truffle is consumed from its published repository, pinned to an exact version
// rather than a bare revision.
Expand All @@ -65,16 +65,16 @@ let appleNativeChecksum = "2a9e41d98e7e746c61cc0a4c61d6505cee5b69977ff4796db6f4d
//
// `exact:` rather than `from:` keeps the lockstep discipline the revision pin
// had: exactly one Truffle across both planes, moved deliberately. Truffle's
// remote carries a plain `v0.7.23` tag on the same commit its release-please
// `truffle-v0.7.23` tag names, so this resolves that exact build through a
// remote carries a plain `v0.7.26` tag on the same commit its release-please
// `truffle-v0.7.26` tag names, so this resolves that exact build through a
// stable requirement.
//
// Keep this equal to `package.version` in
// `apple/GhostteaKit/Compatibility/truffle-swift.lock.json`, whose
// `package.revision` records the commit that version resolves to; the App Store
// readiness check compares the resolved pin against both and fails closed.
let truffleRepository = "https://github.com/vibecook-dev/truffle.git"
let truffleVersion: Version = "0.7.23"
let truffleVersion: Version = "0.7.26"

let sources = "apple/GhostteaKit/Sources"
let tests = "apple/GhostteaKit/Tests"
Expand Down
Loading
Loading