Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 16 additions & 3 deletions apps/mobile/modules/t3-terminal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ The JavaScript contract is intentionally small:
- resize from the native surface is emitted as `{ cols: number, rows: number }`
- remote PTY output is delivered by the existing `WsRpcClient.terminal` RPC stream

The iOS implementation uses the vendored `GhosttyKit.xcframework` built from the same custom-I/O
Ghostty fork used by VVTerm. `T3TerminalView` owns a `libghostty` surface and mirrors VVTerm's
custom I/O model:
The iOS implementation uses the vendored `GhosttyKit.xcframework` built from the Ghostty custom-I/O
fork, with T3's iOS 16 compatibility patch applied. `T3TerminalView` owns a `libghostty` surface and
uses that callback I/O model:

1. initialize libghostty once for the process
2. create one Ghostty app and surface per native view
Expand All @@ -23,3 +23,16 @@ React Native screen and RPC code stay platform-neutral. The renderer backend can
future Android Ghostty build without changing JS.

Vendored Ghostty revision and license details are in `THIRD_PARTY_NOTICES.md`.

## Rebuilding GhosttyKit

The checked-in `GhosttyKit.xcframework` is built from the Ghostty custom-I/O fork (https://github.com/Yash-Singh1/ghostty/tree/custom-io).
Set the directory to the cloned repository checked out on the `custom-io` branch to `GHOSTTY_SOURCE_DIR`.

```bash
apps/mobile/modules/t3-terminal/scripts/build-libghostty-ios16.sh
```

The script builds Ghostty with Zig 0.15.2, strips the iOS archives, and replaces only the
`ios-arm64` and `ios-arm64-simulator` slices. Xcode's Metal toolchain must be installed; if `metal`
fails, run `xcodebuild -downloadComponent MetalToolchain`.
9 changes: 5 additions & 4 deletions apps/mobile/modules/t3-terminal/THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

## Ghostty / libghostty

The iOS terminal renderer vendors `GhosttyKit.xcframework`, a libghostty build produced from
VVTerm's custom-I/O Ghostty fork.
The iOS terminal renderer vendors `GhosttyKit.xcframework`, a libghostty build produced from T3's
iOS 16 support fork. That fork was created from VVTerm's custom-I/O Ghostty fork.

- Upstream project: https://github.com/ghostty-org/ghostty
- Vendored source fork: https://github.com/wiedymi/ghostty
- Vendored revision: `268a0a9d761fb19673f05d28042488e2002300f2`
- Custom-I/O base fork: https://github.com/wiedymi/ghostty/tree/custom-io
- Vendored source fork: https://github.com/Yash-Singh1/ghostty/tree/custom-io
- Vendored revision: `d36c3b8dffd0d756dd5e5f4933962f774a0e6753`
- Reference integration: https://github.com/vivy-company/vvterm
- License: MIT

Expand Down

Large diffs are not rendered by default.

Binary file not shown.

Large diffs are not rendered by default.

Binary file not shown.
2 changes: 1 addition & 1 deletion apps/mobile/modules/t3-terminal/Vendor/libghostty/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
268a0a9d761fb19673f05d28042488e2002300f2
d36c3b8dffd0d756dd5e5f4933962f774a0e6753
2 changes: 1 addition & 1 deletion apps/mobile/modules/t3-terminal/ios/T3TerminalView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ public final class T3TerminalView: ExpoView, UITextFieldDelegate {
supports_selection_clipboard: false,
wakeup_cb: { _ in },
action_cb: { _, _, _ in false },
read_clipboard_cb: { _, _, _ in },
read_clipboard_cb: { _, _, _ in false },
confirm_read_clipboard_cb: { _, _, _, _ in },
write_clipboard_cb: { _, _, _, _, _ in },
close_surface_cb: { _, _ in }
Expand Down
106 changes: 106 additions & 0 deletions apps/mobile/modules/t3-terminal/scripts/build-libghostty-ios16.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/env bash

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MODULE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
VENDOR_DIR="${MODULE_DIR}/Vendor/libghostty"

GHOSTTY_SOURCE_DIR="${GHOSTTY_SOURCE_DIR:-${HOME}/ghostty}"
GHOSTTY_ZIG_VERSION="${GHOSTTY_ZIG_VERSION:-0.15.2}"
GHOSTTY_ZIG="${GHOSTTY_ZIG:-}"

log() {
printf '[libghostty-ios16] %s\n' "$*"
}

die() {
printf '[libghostty-ios16] error: %s\n' "$*" >&2
exit 1
}

require_cmd() {
command -v "$1" >/dev/null 2>&1 || die "missing required command: $1"
}

ensure_zig() {
if [[ -n "${GHOSTTY_ZIG}" ]]; then
[[ -x "${GHOSTTY_ZIG}" ]] || die "GHOSTTY_ZIG is not executable: ${GHOSTTY_ZIG}"
return
fi

if command -v zig >/dev/null 2>&1 && [[ "$(zig version)" == "${GHOSTTY_ZIG_VERSION}" ]]; then
GHOSTTY_ZIG="$(command -v zig)"
return
fi

local cache_dir="${HOME}/.cache/t3code/zig-${GHOSTTY_ZIG_VERSION}"
local archive_arch
archive_arch="$(uname -m)"
case "${archive_arch}" in
arm64) archive_arch="aarch64" ;;
x86_64) archive_arch="x86_64" ;;
*) die "unsupported macOS architecture for Zig download: ${archive_arch}" ;;
esac

GHOSTTY_ZIG="${cache_dir}/zig"
if [[ -x "${GHOSTTY_ZIG}" ]]; then
return
fi

require_cmd curl
require_cmd tar
mkdir -p "${cache_dir}"
log "downloading Zig ${GHOSTTY_ZIG_VERSION}"
curl -fsSL "https://ziglang.org/download/${GHOSTTY_ZIG_VERSION}/zig-${archive_arch}-macos-${GHOSTTY_ZIG_VERSION}.tar.xz" \
| tar -xJ --strip-components=1 -C "${cache_dir}"
}

require_cmd git
require_cmd xcodebuild
require_cmd xcrun
require_cmd rsync
ensure_zig

ghostty_ref="$(git -C "${GHOSTTY_SOURCE_DIR}" rev-parse HEAD)"
log "using Ghostty source: ${GHOSTTY_SOURCE_DIR} @ ${ghostty_ref}"
log "using Zig: ${GHOSTTY_ZIG} ($("${GHOSTTY_ZIG}" version))"
log "building GhosttyKit.xcframework"

(
cd "${GHOSTTY_SOURCE_DIR}"
PATH="$(dirname "${GHOSTTY_ZIG}"):${PATH}" "${GHOSTTY_ZIG}" build \
-Dapp-runtime=none \
-Demit-xcframework=true \
-Demit-macos-app=false \
-Demit-exe=false \
-Demit-docs=false \
-Demit-webdata=false \
-Demit-helpgen=false \
-Demit-terminfo=false \
-Demit-termcap=false \
-Demit-themes=false \
-Doptimize=ReleaseFast \
-Dstrip \
-Dxcframework-target=universal
)

xcframework="${GHOSTTY_SOURCE_DIR}/macos/GhosttyKit.xcframework"
ios_archive="${xcframework}/ios-arm64/libghostty-fat.a"
sim_archive="${xcframework}/ios-arm64-simulator/libghostty-fat.a"
[[ -f "${ios_archive}" ]] || die "missing built iOS archive: ${ios_archive}"
[[ -f "${sim_archive}" ]] || die "missing built iOS simulator archive: ${sim_archive}"

log "stripping iOS archives"
xcrun strip -S -x "${ios_archive}"
xcrun strip -S -x "${sim_archive}"

log "copying iOS archives into ${VENDOR_DIR}/GhosttyKit.xcframework"
cp "${ios_archive}" "${VENDOR_DIR}/GhosttyKit.xcframework/ios-arm64/libghostty-fat.a"
cp "${sim_archive}" "${VENDOR_DIR}/GhosttyKit.xcframework/ios-arm64-simulator/libghostty-fat.a"
rsync -a --delete "${xcframework}/ios-arm64/Headers/" \
"${VENDOR_DIR}/GhosttyKit.xcframework/ios-arm64/Headers/"
rsync -a --delete "${xcframework}/ios-arm64-simulator/Headers/" \
"${VENDOR_DIR}/GhosttyKit.xcframework/ios-arm64-simulator/Headers/"

log "done"
1 change: 1 addition & 0 deletions apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"react-native-shiki-engine": "^0.3.9",
"react-native-svg": "15.15.3",
"react-native-worklets": "0.7.2",
"shiki": "3.23.0",
"tailwind-merge": "^3.5.0",
"uniwind": "^1.6.2"
},
Expand Down
Loading
Loading