Keep non-ASCII startup input as UTF-8 - #15081
Conversation
`cmux workspace create --command` types its command into the new shell as Ghostty startup input. When that command prints an OSC 0 title, the title comes from the bytes Ghostty wrote to the child. Drive the real startup-input path with the issue's exact payload, echo the captured bytes back as program output, and assert the surface title, covering Korean, Japanese, emoji and combining marks. A second test checks that an OSC title with invalid UTF-8 never becomes a Latin-1 title and does not block the next valid one. Fails today: every non-ASCII byte arrives re-encoded as a Latin-1 codepoint, so the title is mojibake. Refs #12915 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bump the Ghostty fork to e168fd31c. `cmux workspace create --command`
passes its command as Ghostty startup input, which the embedded apprt
escaped with std.zig.stringEscape (`\xNN` per non-ASCII byte) and termio
parsed back as one UTF-8 codepoint per escape. Korean, Japanese, emoji
and any other non-ASCII command text reached the shell as mojibake, so an
OSC 0/2 title the command printed showed as mojibake in the workspace
label, sidebar and `cmux workspace list`. The fork cherry-picks upstream
29b82dd80c46 ("config: preserve bytes in hex escapes") and adds a
round-trip test; build-ghosttykit.yml runs both tests before packaging.
Fixes #12915
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
All contributors have signed the CLA ✍️ ✅ |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Warning Review limit reachedNext included review available in 18 minutes. View limit detailsLimit details: You’ve used all 10 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Repository: manaflow-ai/cmux/.coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (7)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
|
|
Merge receipt for |
2604935 coderouter: wait for sticky credential refreshes on a lease-completion signal (manaflow-ai#15087) 369cd16 coderouter: scope org API keys to team-shared accounts (manaflow-ai#15086) 847c919 Keep non-ASCII startup input as UTF-8 (manaflow-ai#15081) a616a2b Remove obsolete bash PR watcher loops (manaflow-ai#15075) # Conflicts: # .github/workflows/build-ghosttykit.yml # .github/workflows/ci-guards.yml
Fixes #12915
Summary
cmux workspace create --command "printf '\033]0;라마바OSC테스트\007'; sleep 90"gave the workspace a mojibake title, while--namewith the same text worked. The OSC decode was fine: the shell never received UTF-8 in the first place.--command(and the other--commandcreation paths) passes its text to Ghostty as startup input. The embedded apprt escapes startup input withstd.zig.stringEscape, which writes each non-ASCII byte as\xNN, and termio parses it back withconfig/string.zig, which encoded each\xNNas a UTF-8 codepoint. So라(EB 9D BC) reachedprintfasC3 AB C2 9D C2 BC, and the title it printed was UTF-8 read as Latin-1. The workspace label, sidebar, tab title,cmux workspace list, notifications and session restore all show the title Ghostty parsed, so every one of them was wrong.The Ghostty fork now carries upstream's fix,
29b82dd80c46("config: preserve bytes in hex escapes"), cherry-picked in manaflow-ai/ghostty#239, so\xNNis one byte again and startup input reaches the shell unchanged. Any non-ASCII text passed with--commandis fixed, not just OSC titles.Regression window. The issue points at 0.64.25, but nothing between v0.64.24 and v0.64.25 touches this path. The Ghostty escape/parse mismatch is older; it became user-visible when
--commandshipped in #9614 (v0.64.23). Titles set with--name, and titles printed by commands typed into a shell, never went through startup input, which is why they looked fine.Trade-offs
text:keybind with\xNNat or above0x80now sends that raw byte rather than the codepoint's UTF-8. That matches upstream and Zig's own string syntax;\u{...}still sends a codepoint.edefce778, so this PR doesn't pull in the newer, unrelated commits on the fork'smain. The fork PR is left open for a maintainer.Testing
Red commit
992bf8eadds the test; fix commit3ec1a57bumps Ghostty;566794apins the GhosttyKit checksum.cmuxTests/GhosttyStartupInputUTF8Testsdrives the real startup-input path: it creates a surface with the exact\033]0;라마바OSC테스트\007payload as initial input, checks the bytes the shell would read, echoes them back and asserts the title is라마바OSC테스트. It repeats this for Japanese, emoji with a ZWJ sequence, and combining marks, and checks that an invalid-UTF-8 title never shows up as Latin-1 and doesn't block the next title.992bf8e: pending, run 36359955943.566794a: pending, run 36361490263 (withGhosttyCopyModeScrollbackTests, which shares the test terminal).parse: hex escapes are bytesandcloneParsed restores Zig-escaped bytespassed in GhosttyKit run 36360076795 ate168fd31c(75 tests), which also published the pinned xcframework.992bf8e(run 36360118764) sent the verbatim repro throughworkspace.createand readworkspace.list: the title came back asprintf '\033]0;ë¼ë§ë°OSCíì¤í¸\007'; sleep 90, and the window title, sidebar row and tab showed the same mojibake. The after-fix tour on566794ais pending.python3 scripts/verify-local.py: 15/15 static checks passed.python3 scripts/swift_file_length_budget.pypassed.Not verified: no local native build or test run on this machine (per the machine-load rule); iOS is untouched.
Changelog
Fixed: Non-ASCII text passed with
--command, such as a Korean terminal title it prints, no longer arrives in the shell as mojibakeChecklist
docs/ghostty-fork.mdrecords the fork change🤖 Generated with Claude Code
Summary by cubic
Fixes #12915: non-ASCII text passed with
cmux workspace create --commandreached the shell as mojibake, so a Korean OSC title printed by the command showed mojibake in the workspace label, sidebar, tab, list, and notifications. Ghostty escaped each non-ASCII byte of startup input as\xNNand termio decoded each escape as a UTF-8 codepoint; the fork now preserves bytes in hex escapes so startup input reaches the shell unchanged. The issue became user-visible when--commandshipped (v0.64.23);--nametitles and titles printed by commands typed into a shell never went through startup input.Side effects
text:keybind that uses\xNNat or above0x80now sends that raw byte;\u{...}still sends a codepoint.Testing
GhosttyStartupInputUTF8Testsdrives the real startup-input path with the issue's exact payload, covering Korean, Japanese, emoji with a ZWJ sequence, and combining marks, plus invalid UTF-8.build-ghosttykit.ymlbefore packaging.Written for commit 7029467. Summary will update on new commits.