fix(coding-agent): reject unverified local clipboard writes

fixes #9618
This commit is contained in:
Armin Ronacher
2026-09-16 00:08:02 +02:00
parent 4c2d91339a
commit 3349e1db18
3 changed files with 14 additions and 2 deletions
+1
View File
@@ -14,6 +14,7 @@
### Fixed
- Fixed local clipboard failures reporting success when the terminal ignored the fallback OSC 52 write ([#9618](https://github.com/earendil-works/pi/issues/9618)).
- Capped agent-level retry backoff at `retry.maxAgentDelayMs` (60s by default) so long retry runs stay responsive during prolonged transient outages ([#8826](https://github.com/earendil-works/pi/issues/8826)).
- Fixed direct RPC `steer` and `follow_up` commands bypassing extension `input` handlers ([#8718](https://github.com/earendil-works/pi/issues/8718)).
- Fixed premature missing-model errors after login by waiting for catalog discovery. Radius now defaults to `balanced`, falling back to the first available Radius model when needed.
+1 -1
View File
@@ -72,6 +72,6 @@ export async function copyToClipboard(text: string): Promise<void> {
}
}
}
if (isRemoteSession() || !copied) copied = emitOsc52(text) || copied;
if (isRemoteSession()) copied = emitOsc52(text) || copied;
if (!copied) throw new Error("Failed to copy to clipboard");
}
+12 -1
View File
@@ -157,13 +157,24 @@ describe("copyToClipboard", () => {
expect(mocks.command.mock.calls.map(([name]) => name)).toEqual(["wl-copy", "xclip", "xsel"]);
expect(osc52Writes).toHaveLength(0);
});
test("uses OSC 52 when native and command writes fail", async () => {
test("local Linux failure does not report an unverified OSC 52 write as success", async () => {
// Regression test for #9618.
mocks.platform.mockReturnValue("linux");
vi.stubEnv("DISPLAY", ":0");
mocks.command.mockResolvedValue(undefined);
await expect(copyToClipboard("hello")).rejects.toThrow("Failed to copy to clipboard");
expect(mocks.command.mock.calls.map(([name]) => name)).toEqual(["xclip", "xsel"]);
expect(osc52Writes).toHaveLength(0);
});
test("uses OSC 52 when native and command writes fail in a remote session", async () => {
vi.stubEnv("SSH_CONNECTION", "client server");
mocks.clipboard.setText.mockRejectedValue(new Error("native failed"));
mocks.command.mockResolvedValue(undefined);
await copyToClipboard("hello");
expect(osc52Writes).toHaveLength(1);
});
test("does not emit oversized OSC 52 payloads", async () => {
vi.stubEnv("SSH_CONNECTION", "client server");
mocks.clipboard.setText.mockRejectedValue(new Error("native failed"));
mocks.command.mockResolvedValue(undefined);
await expect(copyToClipboard("x".repeat(80_000))).rejects.toThrow("Failed to copy to clipboard");