mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-15 00:21:09 -07:00
fix(cli): use OSC-52 clipboard copy in Windows Terminal (#16920)
Co-authored-by: Jack Wotherspoon <jackwoth@google.com>
This commit is contained in:
@@ -109,6 +109,18 @@ const pickTty = (): Promise<TtyTarget> =>
|
||||
});
|
||||
|
||||
const getStdioTty = (): TtyTarget => {
|
||||
// On Windows, prioritize stdout to prevent shell-specific formatting (e.g., PowerShell's
|
||||
// red stderr) from corrupting the raw escape sequence payload.
|
||||
if (process.platform === 'win32') {
|
||||
if (process.stdout?.isTTY)
|
||||
return { stream: process.stdout, closeAfter: false };
|
||||
if (process.stderr?.isTTY)
|
||||
return { stream: process.stderr, closeAfter: false };
|
||||
return null;
|
||||
}
|
||||
|
||||
// On non-Windows platforms, prioritize stderr to avoid polluting stdout,
|
||||
// preserving it for potential redirection or piping.
|
||||
if (process.stderr?.isTTY)
|
||||
return { stream: process.stderr, closeAfter: false };
|
||||
if (process.stdout?.isTTY)
|
||||
@@ -140,10 +152,13 @@ const isWSL = (): boolean =>
|
||||
process.env['WSL_INTEROP'],
|
||||
);
|
||||
|
||||
const isWindowsTerminal = (): boolean =>
|
||||
process.platform === 'win32' && Boolean(process.env['WT_SESSION']);
|
||||
|
||||
const isDumbTerm = (): boolean => (process.env['TERM'] ?? '') === 'dumb';
|
||||
|
||||
const shouldUseOsc52 = (tty: TtyTarget): boolean =>
|
||||
Boolean(tty) && !isDumbTerm() && (isSSH() || isWSL());
|
||||
Boolean(tty) && !isDumbTerm() && (isSSH() || isWSL() || isWindowsTerminal());
|
||||
|
||||
const safeUtf8Truncate = (buf: Buffer, maxBytes: number): Buffer => {
|
||||
if (buf.length <= maxBytes) return buf;
|
||||
@@ -176,6 +191,27 @@ const wrapForScreen = (seq: string): string => {
|
||||
|
||||
const writeAll = (stream: Writable, data: string): Promise<void> =>
|
||||
new Promise<void>((resolve, reject) => {
|
||||
// On Windows, writing directly to the underlying file descriptor bypasses
|
||||
// application-level stream interception (e.g., by the Ink UI framework).
|
||||
// This ensures the raw OSC-52 escape sequence reaches the terminal host uncorrupted.
|
||||
const fd = (stream as unknown as { fd?: number }).fd;
|
||||
if (
|
||||
process.platform === 'win32' &&
|
||||
typeof fd === 'number' &&
|
||||
(stream === process.stdout || stream === process.stderr)
|
||||
) {
|
||||
try {
|
||||
fs.writeSync(fd, data);
|
||||
resolve();
|
||||
return;
|
||||
} catch (e) {
|
||||
debugLogger.warn(
|
||||
'Direct write to TTY failed, falling back to stream write',
|
||||
e,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const onError = (err: unknown) => {
|
||||
cleanup();
|
||||
reject(err as Error);
|
||||
|
||||
Reference in New Issue
Block a user