Browse Source

fix: centralize OSC 52 clipboard support for SSH sessions (#8974)

b3nw 1 month ago
parent
commit
3d095e7fe7

+ 0 - 10
packages/opencode/src/cli/cmd/tui/app.tsx

@@ -200,11 +200,6 @@ function App() {
   renderer.console.onCopySelection = async (text: string) => {
     if (!text || text.length === 0) return
 
-    const base64 = Buffer.from(text).toString("base64")
-    const osc52 = `\x1b]52;c;${base64}\x07`
-    const finalOsc52 = process.env["TMUX"] ? `\x1bPtmux;\x1b${osc52}\x1b\\` : osc52
-    // @ts-expect-error writeOut is not in type definitions
-    renderer.writeOut(finalOsc52)
     await Clipboard.copy(text)
       .then(() => toast.show({ message: "Copied to clipboard", variant: "info" }))
       .catch(toast.error)
@@ -627,11 +622,6 @@ function App() {
         }
         const text = renderer.getSelection()?.getSelectedText()
         if (text && text.length > 0) {
-          const base64 = Buffer.from(text).toString("base64")
-          const osc52 = `\x1b]52;c;${base64}\x07`
-          const finalOsc52 = process.env["TMUX"] ? `\x1bPtmux;\x1b${osc52}\x1b\\` : osc52
-          /* @ts-expect-error */
-          renderer.writeOut(finalOsc52)
           await Clipboard.copy(text)
             .then(() => toast.show({ message: "Copied to clipboard", variant: "info" }))
             .catch(toast.error)

+ 0 - 5
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx

@@ -697,11 +697,6 @@ export function Session() {
           return
         }
 
-        const base64 = Buffer.from(text).toString("base64")
-        const osc52 = `\x1b]52;c;${base64}\x07`
-        const finalOsc52 = process.env["TMUX"] ? `\x1bPtmux;\x1b${osc52}\x1b\\` : osc52
-        /* @ts-expect-error */
-        renderer.writeOut(finalOsc52)
         Clipboard.copy(text)
           .then(() => toast.show({ message: "Message copied to clipboard!", variant: "success" }))
           .catch(() => toast.show({ message: "Failed to copy to clipboard", variant: "error" }))

+ 0 - 5
packages/opencode/src/cli/cmd/tui/ui/dialog.tsx

@@ -141,11 +141,6 @@ export function DialogProvider(props: ParentProps) {
         onMouseUp={async () => {
           const text = renderer.getSelection()?.getSelectedText()
           if (text && text.length > 0) {
-            const base64 = Buffer.from(text).toString("base64")
-            const osc52 = `\x1b]52;c;${base64}\x07`
-            const finalOsc52 = process.env["TMUX"] ? `\x1bPtmux;\x1b${osc52}\x1b\\` : osc52
-            /* @ts-expect-error */
-            renderer.writeOut(finalOsc52)
             await Clipboard.copy(text)
               .then(() => toast.show({ message: "Copied to clipboard", variant: "info" }))
               .catch(toast.error)

+ 16 - 0
packages/opencode/src/cli/cmd/tui/util/clipboard.ts

@@ -5,6 +5,21 @@ import { lazy } from "../../../../util/lazy.js"
 import { tmpdir } from "os"
 import path from "path"
 
+/**
+ * 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.
+ */
+function writeOsc52(text: string): void {
+  if (!process.stdout.isTTY) return
+  const base64 = Buffer.from(text).toString("base64")
+  const osc52 = `\x1b]52;c;${base64}\x07`
+  // tmux and screen require DCS passthrough wrapping
+  const passthrough = process.env["TMUX"] || process.env["STY"]
+  const sequence = passthrough ? `\x1bPtmux;\x1b${osc52}\x1b\\` : osc52
+  process.stdout.write(sequence)
+}
+
 export namespace Clipboard {
   export interface Content {
     data: string
@@ -123,6 +138,7 @@ export namespace Clipboard {
   })
 
   export async function copy(text: string): Promise<void> {
+    writeOsc52(text)
     await getCopyMethod()(text)
   }
 }