Repository navigation
Claude/scrub kitty identity env #88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -70,12 +70,69 @@ func normalizeEnv(env []string) []string { | |
| normalized = mergeEnv(normalized, env) | ||
| } | ||
|
|
||
| normalized = scrubGraphicsIdentityEnv(normalized) | ||
|
|
||
| normalized = appendDefaultEnv(normalized, "TERM", "xterm-256color") | ||
| normalized = appendDefaultEnv(normalized, "COLORTERM", "truecolor") | ||
|
|
||
| return normalized | ||
| } | ||
|
|
||
| // kittyIdentityVars are environment variables that mark the host terminal as | ||
| // Kitty- or Ghostty-class. Apps detect Kitty graphics-protocol support purely | ||
| // from these (e.g. Terminal.Gui's KittyGraphicsSupportDetector keys off | ||
| // KITTY_WINDOW_ID, never a query/response) — see also the TERM_PROGRAM handling | ||
| // in scrubGraphicsIdentityEnv. | ||
| // | ||
| // tuirec presents a deterministic, sixel-capable xterm identity: TERM is forced | ||
| // to xterm-256color and the DA1/geometry interceptor advertises sixel. The agg | ||
| // replay pipeline renders sixel but not Kitty graphics. If these markers leak in | ||
| // from the recording shell (i.e. recording from inside kitty/ghostty), the app | ||
| // detects Kitty, prefers it over sixel, and emits Kitty graphics that agg cannot | ||
| // render — the GIF comes out blank. Strip them so the app uses the sixel path | ||
| // tuirec actually supports. | ||
| var kittyIdentityVars = map[string]bool{ | ||
| "KITTY_WINDOW_ID": true, | ||
| "KITTY_PID": true, | ||
| "KITTY_INSTALLATION_DIR": true, | ||
| "KITTY_LISTEN_ON": true, | ||
| "KITTY_PUBLIC_KEY": true, | ||
| "GHOSTTY_RESOURCES_DIR": true, | ||
| "GHOSTTY_BIN_DIR": true, | ||
| } | ||
|
|
||
| // scrubGraphicsIdentityEnv removes the environment variables that would make a | ||
| // recorded app believe it is running under a Kitty graphics-capable terminal. | ||
| // TERM_PROGRAM is only dropped when it names a Kitty-class terminal (kitty or | ||
| // ghostty), so unrelated values (vscode, iTerm.app, WezTerm, Apple_Terminal, | ||
| // ...) and any app behavior keyed off them are left untouched. | ||
| func scrubGraphicsIdentityEnv(env []string) []string { | ||
| dropTermProgram := false | ||
| for _, entry := range env { | ||
| if key, ok := envKey(entry); ok && key == "TERM_PROGRAM" { | ||
| value := entry[len(key)+1:] | ||
| if strings.EqualFold(value, "kitty") || strings.EqualFold(value, "ghostty") { | ||
| dropTermProgram = true | ||
| break | ||
| } | ||
| } | ||
| } | ||
|
|
||
| filtered := env[:0] | ||
| for _, entry := range env { | ||
| key, ok := envKey(entry) | ||
| if ok && kittyIdentityVars[key] { | ||
| continue | ||
| } | ||
| if ok && dropTermProgram && (key == "TERM_PROGRAM" || key == "TERM_PROGRAM_VERSION") { | ||
|
Comment on lines
+124
to
+127
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When tuirec is launched from kitty or ghostty, the inherited environment commonly includes Useful? React with 👍 / 👎. |
||
| continue | ||
| } | ||
| filtered = append(filtered, entry) | ||
| } | ||
|
|
||
| return filtered | ||
| } | ||
|
|
||
| func mergeEnv(base []string, overrides []string) []string { | ||
| merged := append([]string{}, base...) | ||
| for _, override := range overrides { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CLAUDE.mdexplicitly requires “No global mutable state,” but this package-level map can be mutated by any code in packageptyand would changescrubGraphicsIdentityEnvbehavior globally. Please make this immutable in practice, for example by using aswitch/helper predicate or a local unexported slice that is not used as mutable state.Useful? React with 👍 / 👎.