Skip to content

[BUG] /share clipboard copy fails over SSH #9374

Closed

Description

@mmabrouk

Description

The /share command fails to copy the share URL to the clipboard when using OpenCode over SSH, even with a terminal that supports OSC 52 clipboard escape sequences (Ghostty in this case).

Observed behavior:

  • Session is created successfully
  • Toast message "Share URL copied to clipboard!" appears
  • Clipboard remains empty - nothing is actually copied
    Expected behavior:
  • The share URL should be copied to the clipboard via OSC 52 escape sequence, which works over SSH when the terminal emulator supports it

Plugins

None

OpenCode version

1.1.25

Steps to reproduce

  1. SSH into a remote Linux server from a terminal that supports OSC 52 (e.g., Ghostty with default settings)
  2. Start OpenCode: opencode
  3. Have a conversation or start a new session
  4. Run /share command
  5. Observe: Toast shows "Share URL copied to clipboard!" but clipboard is empty

Screenshot and/or share link

N/A (cannot share because clipboard copy doesn't work 😅)

Operating System

  • Local machine: macOS with Ghostty 1.2.3 - Remote server: Ubuntu 24.04 (Linux 6.8.0-90-generic)

Terminal

Ghostty 1.2.3 (stable) - connected via SSH to remote Linux server

Activity

  1. added
    opentuiThis relates to changes in v1.0, now that opencode uses opentui
    on Jan 19, 2026
  2. github-actions commented on Jan 19, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    Feel free to ignore if none of these address your specific case.

  3. mmabrouk commented on Jan 19, 2026

    @mmabrouk
    Author

    I am adding here a bit of research about the issue discovered with the agent:

    Root Cause Analysis:

    After investigating the source code (packages/opencode/src/cli/cmd/tui/util/clipboard.ts), I found that:

    1. OpenCode correctly implements OSC 52 in the writeOsc52() function (lines 13-21)
    2. The function writes the escape sequence via process.stdout.write(sequence)
    3. However, when the TUI is running, process.stdout appears to be intercepted by the opentui rendering framework
    4. The OSC 52 escape sequence gets captured by the TUI layer instead of being passed through to the terminal emulator
    5. The native fallback (xclip) also fails over SSH because there's no X11 display ($DISPLAY is empty) [this assumes my setup, opencode over simple ssh]

    Proof that OSC 52 works in my terminal:

    Running this directly in Ghostty successfully copies to clipboard:
    printf '\e]52;c;%s\a' "$(echo -n 'test' | base64)"

    Suggested fix:

    What claude suggest for a fix it to write directly to /dev/tty instead of process.stdout. I don't have much expertise in these systems, so I cannot judge, however it feels there might be lots of edge cases to consider.

    Yes, there's a simple fix. Looking at the code:
    function writeOsc52(text: string): void {
    if (!process.stdout.isTTY) return
    const base64 = Buffer.from(text).toString("base64")
    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) // <-- This gets intercepted by TUI
    }

    The fix: Write directly to /dev/tty instead of process.stdout:

    import { openSync, writeSync, closeSync } from "fs"
    function writeOsc52(text: string): void {
    if (!process.stdout.isTTY) return
    const base64 = Buffer.from(text).toString("base64")
    const osc52 = \x1b]52;c;${base64}\x07
    const passthrough = process.env["TMUX"] || process.env["STY"]
    const sequence = passthrough ? \x1bPtmux;\x1b${osc52}\x1b\\ : osc52

    try {
    const fd = openSync("/dev/tty", "w")
    writeSync(fd, sequence)
    closeSync(fd)
    } catch {
    // Fallback to stdout if /dev/tty isn't available
    process.stdout.write(sequence)
    }
    }

    Why this works: /dev/tty is a direct handle to the controlling terminal, bypassing any stdout redirection or interception by the TUI framework.

  4. aspiers commented on Mar 2, 2026

    @aspiers
    Contributor

    Looks like #12129 fixes this.

  5. mmabrouk commented on Mar 2, 2026

    @mmabrouk
    Author

    Yes this indeed was fixed. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingopentuiThis relates to changes in v1.0, now that opencode uses opentui

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions