Skip to content

Replace xterm.js with Ghostty libghostty-vt in the workspace terminal - #81

Draft
sambitcreate wants to merge 6 commits into
mainfrom
cursor/libghostty-terminal-4228
Draft

Replace xterm.js with Ghostty libghostty-vt in the workspace terminal#81
sambitcreate wants to merge 6 commits into
mainfrom
cursor/libghostty-terminal-4228

Conversation

@sambitcreate

@sambitcreate sambitcreate commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Summary

The first revision’s custom get_line canvas host did not match T3 Code’s official libghostty-vt ABI and loaded WASM via node:fs on file: URLs, which fails in the sandboxed Electron renderer.

This update vendors T3 Code’s MIT browser adapter:

  • Official ghostty-vt.wasm pinned at 9f62873bf195e4d8a762d768a1405a5f2f7b1697
  • 112-byte ghostty-write-pty.wasm trampoline for terminal-generated PTY replies
  • Runtime type layouts, core snapshots, Canvas 2D renderer, IME/selection/scrollback surface
  • Symbols Nerd Font Mono for prompt glyphs
  • Renderer fetch uses compile-time new URL() literals in wasm-assets.ts so Vite emits hashed wasm files
  • Node unit tests load ./vendor/${filename} through a dynamic URL so tsx does not rewrite it to a cache path without vendor/
  • assetsInlineLimit keeps the 112-byte trampoline as a real file instead of a data: URL
  • Production build fails if the wasm/font assets are not emitted
  • Host JS stays on Aiden’s ES2020 TypeScript lib (no replaceAll / Array.at / toSorted)

PTY ownership in main/services/terminal.ts is unchanged.

Test plan

  • npm run type-check / npm run lint / npm run test:ghostty-terminal
  • npm run build (must emit hashed ghostty-vt*.wasm and ghostty-write-pty*.wasm)
  • Deterministic Electron E2E (tests/e2e/terminal.spec.ts)
  • Open/split/hide terminal, type a command, scrollback, copy/paste, Cmd/Ctrl+J
Open in Web Open in Cursor 

cursoragent and others added 6 commits September 2, 2026 00:57
Keep node-pty sessions, snapshots, and TERM=xterm-256color, and parse VT
output with Ghostty's WASM engine plus an Aiden canvas surface.

Co-authored-by: Sambit Biswas <sambitcreate@users.noreply.github.com>
Replace the incomplete custom VT canvas with T3's MIT runtime, write-pty
trampoline, core snapshots, and surface (IME, scrollback, selection). Load
WASM through fetch so packaged Electron file: builds work, and fail the
production build if the wasm/font assets are missing.

Co-authored-by: Sambit Biswas <sambitcreate@users.noreply.github.com>
T3's adapter uses replaceAll, Array.at, and toSorted, which fail tsc here.

Co-authored-by: Sambit Biswas <sambitcreate@users.noreply.github.com>
Vite only copies new URL(..., import.meta.url) when the path is a
compile-time literal. The runtime string argument never emitted
ghostty-vt.wasm, so production verify and Electron E2E failed. Keep the
112-byte write-pty trampoline as a real file with ?no-inline.

Co-authored-by: Sambit Biswas <sambitcreate@users.noreply.github.com>
Vite still needs compile-time new URL() to emit hashed wasm, but tsx
rewrites those literals and ?no-inline made npm test fail after the
production emit fix. Load vendor files from disk in Node, and keep the
Vite URLs in wasm-assets.ts.

Co-authored-by: Sambit Biswas <sambitcreate@users.noreply.github.com>
tsx rewrites static new URL(..., import.meta.url) to a cache directory
that does not contain vendor/, so GhosttyRuntime.load() failed after the
wasm-assets split. Keep Vite literals in wasm-assets.ts only.

Co-authored-by: Sambit Biswas <sambitcreate@users.noreply.github.com>
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.

2 participants