mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
feat(coding-agent): add PI_CLIPBOARD_OSC52 to force OSC 52 copies
Sends copied text to the terminal with OSC 52 after the local clipboard write, as over SSH, for remote clients without SSH variables such as multiplexer attaches and remote IDE daemons. closes #10826, closes #10835, closes #10114
This commit is contained in:
parent
b6d505cd1f
commit
3e477eab5f
4 changed files with 29 additions and 1 deletions
|
|
@ -14,6 +14,7 @@
|
|||
- Added `reachesTools` to tool definitions, so tools that reach other tools (such as `codemode` and `tool_search`) declare which tools a call may reach; the MCP extension uses it to wait for the servers a call needs and to decide whether a replacement `codemode` or `tool_search` tool can reach MCP tools
|
||||
- Added `aliases` to tool namespaces; codemode's `describeNamespace()` and the `namespace` option of `searchTools()` match them, and MCP namespaces use the server name
|
||||
- Added per-key OpenRouter model lists: with an OpenRouter key, Pi lists only the chat models that key may use, with the key's context size, max output, and prices, including guardrails and regional endpoints set as the base URL in `models.json`. The list is saved and used offline ([#10353](https://github.com/earendil-works/pi/issues/10353))
|
||||
- Added `PI_CLIPBOARD_OSC52=1` to send copied text to the terminal with OSC 52 after the local clipboard write, so copies reach a remote client's clipboard when Pi cannot detect the remote session, such as multiplexer attaches from another machine or remote IDE daemons ([#10826](https://github.com/earendil-works/pi/issues/10826), [#10835](https://github.com/earendil-works/pi/issues/10835), [#10114](https://github.com/earendil-works/pi/issues/10114))
|
||||
- Added elapsed time while a codemode script runs and its total time once finished to the codemode tool row, like bash rows ([#10708](https://github.com/earendil-works/pi/issues/10708))
|
||||
|
||||
### Changed
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ These variables are read by Pi itself:
|
|||
| `PI_SHARE_VIEWER_URL` | Override the base URL used by `/share` |
|
||||
| `PI_RADIUS_GATEWAY` | Override the Radius gateway origin used by `/bug` uploads |
|
||||
| `PI_HARDWARE_CURSOR` | Set to `1` to show the hardware cursor; see [Terminal setup](terminal-setup.md) |
|
||||
| `PI_CLIPBOARD_OSC52` | Set to `1` to also send copied text to the terminal with OSC 52 after the local clipboard write, as Pi does over SSH. Use it when a remote client reaches Pi without SSH variables, such as a multiplexer attached from another machine or a remote IDE daemon |
|
||||
| `PI_HYPERLINKS` | Override OSC 8 hyperlink detection with `1`, `0`, or `auto` |
|
||||
| `PI_PROGRAM_STATUS` | Override OSC 7501 program status detection: `1` always reports, `0` never reports; otherwise Pi reports only after the terminal confirms support. See [Terminal setup](terminal-setup.md#program-status) |
|
||||
| `PI_IMAGE_PROTOCOL` | Override inline image detection with `kitty`, `iterm2`, `none`, or `auto` |
|
||||
|
|
|
|||
|
|
@ -8,8 +8,13 @@ import { isWSL } from "./wsl.ts";
|
|||
|
||||
const MAX_OSC52_ENCODED_LENGTH = 100_000;
|
||||
|
||||
/**
|
||||
* Remote sessions also emit OSC 52 so the client terminal receives the copy. PI_CLIPBOARD_OSC52=1
|
||||
* covers remote clients that leave no SSH markers, such as multiplexer attaches (#10114, #10835)
|
||||
* or IDE daemons (#10826).
|
||||
*/
|
||||
function isRemoteSession(env: NodeJS.ProcessEnv): boolean {
|
||||
return Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION);
|
||||
return Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION || env.PI_CLIPBOARD_OSC52 === "1");
|
||||
}
|
||||
|
||||
function emitOsc52(text: string): boolean {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ beforeEach(() => {
|
|||
"WT_SESSION",
|
||||
"WSL_DISTRO_NAME",
|
||||
"WSLENV",
|
||||
"PI_CLIPBOARD_OSC52",
|
||||
])
|
||||
vi.stubEnv(name, "");
|
||||
mocks.platform.mockReturnValue("darwin");
|
||||
|
|
@ -150,6 +151,26 @@ describe("copyToClipboard", () => {
|
|||
expect(osc52Writes).toHaveLength(1);
|
||||
expect(mocks.command).not.toHaveBeenCalled();
|
||||
});
|
||||
test.each([
|
||||
["darwin", undefined],
|
||||
["win32", undefined],
|
||||
["linux", ":99"],
|
||||
] as const)("PI_CLIPBOARD_OSC52=1 emits OSC 52 after a successful %s copy", async (platform, display) => {
|
||||
// Regression test for #10826, #10835, #10114: remote clients without SSH markers.
|
||||
mocks.platform.mockReturnValue(platform);
|
||||
if (display) vi.stubEnv("DISPLAY", display);
|
||||
vi.stubEnv("PI_CLIPBOARD_OSC52", "1");
|
||||
await copyToClipboard("hello");
|
||||
if (platform === "linux") {
|
||||
expect(mocks.command).toHaveBeenCalledWith("xclip", ["-selection", "clipboard"], {
|
||||
input: "hello",
|
||||
timeoutMs: 5000,
|
||||
});
|
||||
} else {
|
||||
expect(mocks.clipboard.setText).toHaveBeenCalledWith("hello");
|
||||
}
|
||||
expect(osc52Writes).toEqual([`\x1b]52;c;${Buffer.from("hello").toString("base64")}\x07`]);
|
||||
});
|
||||
test("a rejected native write falls back to pbcopy", async () => {
|
||||
mocks.clipboard.setText.mockRejectedValue(new Error("native failed"));
|
||||
await copyToClipboard("hello");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue