diff --git a/packages/opencode/src/cli/cmd/tui/util/clipboard.ts b/packages/opencode/src/cli/cmd/tui/util/clipboard.ts index 4be6787346d..7057aec4b00 100644 --- a/packages/opencode/src/cli/cmd/tui/util/clipboard.ts +++ b/packages/opencode/src/cli/cmd/tui/util/clipboard.ts @@ -4,11 +4,15 @@ import clipboardy from "clipboardy" import { lazy } from "../../../../util/lazy.js" import { tmpdir } from "os" import path from "path" +import fs from "fs" /** * Writes text to clipboard via OSC 52 escape sequence. * This allows clipboard operations to work over SSH by having * the terminal emulator handle the clipboard locally. + * + * Writes to /dev/tty directly to bypass terminal multiplexers + * (Zellij, tmux, screen) that intercept OSC52 on stdout. */ function writeOsc52(text: string): void { if (!process.stdout.isTTY) return @@ -16,7 +20,18 @@ function writeOsc52(text: string): void { const osc52 = `\x1b]52;c;${base64}\x07` const passthrough = process.env["TMUX"] || process.env["STY"] const sequence = passthrough ? `\x1bPtmux;\x1b${osc52}\x1b\\` : osc52 - process.stdout.write(sequence) + + // Write to /dev/tty directly to bypass terminal multiplexers. + // SSH_TTY is set when connected via SSH, otherwise use /dev/tty. + const ttyPath = process.env["SSH_TTY"] || "/dev/tty" + try { + const fd = fs.openSync(ttyPath, "w") + fs.writeSync(fd, sequence) + fs.closeSync(fd) + } catch { + // Fallback to stdout if /dev/tty is unavailable (e.g., Windows) + process.stdout.write(sequence) + } } export namespace Clipboard {