Identified URL as issue, not PR.
UnderstandReviewed related issue and referenced PR.
UnderstandDetected uncommitted changes blocking git operations.
UnderstandAsked user for commit strategy on unstaged files.
PlanYou are given one or more GitHub PR URLs: https://github.com/badlogic/pi-mono/issues/1069
For each PR URL, do the following in order:
packages/*/CHANGELOG.md files. Report whether an entry exists. If missing, state that a changelog entry is required before merge and that you will add it if the user decides to merge. Follow the changelog format rules in AGENTS.md. Verify:
### Breaking Changes, ### Added, ### Fixed, etc.)Fixed foo ([#123](https://github.com/badlogic/pi-mono/pull/123) by [@user](https://github.com/user))### Breaking Changes, not just ### FixedOutput format per PR: PR: Changelog:
If no issues are found, say so under Bad and Ugly.
The URL points to an issue, not a PR. Let me read the issue:
This is an issue (#1069), not a PR. The issue requests OSC 52 clipboard support for SSH/mosh sessions.
Let me gather more context by reading the referenced PR #415 and the current clipboard implementation:
Let me find where PR #415 implemented OSC 52 to understand the pattern:
Issue #1069 Summary (Not a PR)
This is a feature request issue, not a pull request. There is no code to review.
Issue Details:
Request:
The /copy command fails over SSH with "install xclip or xsel" even though the user's terminal supports OSC 52 escape sequences. The issue asks for pi to detect remote sessions and use OSC 52 (terminal-based clipboard) instead of relying on native clipboard tools.
Current Implementation:
packages/coding-agent/src/utils/clipboard.ts only supports:
pbcopyclipwl-copy (Wayland), xclip/xsel (X11)No fallback for remote/SSH sessions.
User's Proof of Concept: The user provided a working extension that uses OSC 52:
function copyViaOSC52(text: string): void { const encoded = Buffer.from(text).toString("base64"); process.stdout.write(`\x1b]52;c;${encoded}\x07`);}Referenced PR #415:
Merged 2026-01-03. Added OSC 52 for OAuth login URLs specifically for mobile SSH users. However, I found no OSC 52 code in the current codebase (the commit d42a3d71 mentions "make OAuth login URL clickable" but uses OSC 8 hyperlinks, not OSC 52).
Next Steps: If you want me to implement this feature, I can:
SSH_CLIENT, SSH_TTY, SSH_CONNECTION env vars)copyToClipboard() in clipboard.tsWould you like me to proceed with implementation?
any harm in just emitting that anyways? irrespective of whether the terminal supports it or not? any harm in that?
No real harm. The possibilities:
The only minor issues:
Simplest approach: always emit OSC 52 as a fallback when native tools fail. Change the current "throw error" path to "try OSC 52, then succeed silently with a hopeful message."
// Instead of throwing, fall back to OSC 52const encoded = Buffer.from(text).toString("base64");process.stdout.write(`\x1b]52;c;${encoded}\x07`);This way:
The user gets clipboard functionality in more scenarios with no downside. Want me to implement it?
does that fix the users issue?
if we only emit if native tools failß
Yes. The user's scenario:
The OSC 52 sequence travels through the SSH connection to the user's terminal emulator, which handles the clipboard operation locally. That's exactly what the user wants.
what if the remote has xclip/xsel?
Good catch. If remote has xclip/xsel:
So "fallback on failure" doesn't cover this case. Need to detect SSH and prefer OSC 52:
const isSSH = !!(process.env.SSH_CLIENT || process.env.SSH_TTY || process.env.SSH_CONNECTION);
if (isSSH) { // Emit OSC 52 - goes to user's local terminal const encoded = Buffer.from(text).toString("base64"); process.stdout.write(`\x1b]52;c;${encoded}\x07`); return;}// Otherwise use native tools...Or emit both (native + OSC 52) always, but that's wasteful and could cause double-copy weirdness on local sessions.
SSH detection is the cleaner approach.
why not just always emit this shit?
You're right. Just always emit OSC 52:
The whole function becomes:
export function copyToClipboard(text: string): void { const encoded = Buffer.from(text).toString("base64"); process.stdout.write(`\x1b]52;c;${encoded}\x07`);}Delete all the platform detection, native tool fallbacks, Wayland vs X11 logic. 50 lines → 3 lines.
Only theoretical downside: terminals with OSC 52 disabled (rare, usually security-paranoid setups). But those users probably know what they're doing and can enable it.
Want me to implement this?
no, we need to keep the native tools, we just emit this on top of that?
Got it. Belt and suspenders:
export function copyToClipboard(text: string): void { // Always emit OSC 52 - works over SSH, harmless locally const encoded = Buffer.from(text).toString("base64"); process.stdout.write(`\x1b]52;c;${encoded}\x07`); // Also try native tools (best effort, don't throw on failure) try { // ... existing platform logic ... } catch { // Ignore - OSC 52 already emitted }}Want me to implement?
yes
Pre-existing error in daxnuts.ts (unrelated to my changes). Let me add the changelog entry:
Done. Changes:
packages/coding-agent/src/utils/clipboard.ts
copyToClipboard()packages/coding-agent/CHANGELOG.md
### AddedThe /copy command now:
Note: Pre-existing TS error in daxnuts.ts unrelated to this change.
ok, commited and pushed?
There are uncommitted changes from another agent in:
packages/coding-agent/src/modes/interactive/components/index.tspackages/coding-agent/src/modes/interactive/interactive-mode.tsI can't stash or checkout those files (would destroy their work). Options:
What would you like me to do?
are we good to commit anow? also have changelog entries
My OSC 52 commit is already done (branch ahead by 1). But I can't push because git pull --rebase fails with unstaged changes.
Are you asking me to commit the daxnuts changes too? If so, I'd be committing another agent's work. Should I:
Which do you prefer?
function copyViaOSC52(text: string): void { const encoded = Buffer.from(text).toString("base64"); process.stdout.write(`\x1b]52;c;${encoded}\x07`);}// Instead of throwing, fall back to OSC 52const encoded = Buffer.from(text).toString("base64");process.stdout.write(`\x1b]52;c;${encoded}\x07`);const isSSH = !!(process.env.SSH_CLIENT || process.env.SSH_TTY || process.env.SSH_CONNECTION);
if (isSSH) { // Emit OSC 52 - goes to user's local terminal const encoded = Buffer.from(text).toString("base64"); process.stdout.write(`\x1b]52;c;${encoded}\x07`); return;}// Otherwise use native tools...export function copyToClipboard(text: string): void { const encoded = Buffer.from(text).toString("base64"); process.stdout.write(`\x1b]52;c;${encoded}\x07`);}export function copyToClipboard(text: string): void { // Always emit OSC 52 - works over SSH, harmless locally const encoded = Buffer.from(text).toString("base64"); process.stdout.write(`\x1b]52;c;${encoded}\x07`); // Also try native tools (best effort, don't throw on failure) try { // ... existing platform logic ... } catch { // Ignore - OSC 52 already emitted }}