fix(coding-agent): keep clipboard helpers out of pi's process group so Ctrl+Z does not stop them

closes #11179
This commit is contained in:
Mario Zechner 2026-10-20 20:49:48 +02:00
parent 38847563f4
commit f8ab362cca
3 changed files with 14 additions and 0 deletions

View file

@ -18,6 +18,7 @@
- Fixed HTML export showing literal asterisks for Markdown bold and italic next to CJK punctuation ([#3353](https://github.com/earendil-works/pi/issues/3353), [#10154](https://github.com/earendil-works/pi/issues/10154))
- Fixed the terminal staying in mouse-tracking, focus-reporting, Kitty keyboard, and alternate-screen modes when pi exits without its normal terminal teardown, which flooded the shell prompt with escape sequences ([#11170](https://github.com/earendil-works/pi/issues/11170))
- Fixed concurrent extension `select`/`confirm`/`input`/`editor` dialogs and inline `custom()` components in interactive mode: a second dialog replaced the first and the first promise never settled; closing the visible dialog now shows the previous one again ([#11166](https://github.com/earendil-works/pi/issues/11166), [#9909](https://github.com/earendil-works/pi/issues/9909))
- Fixed pasting in the shell hanging after copying text in pi and suspending it with Ctrl+Z on Linux: the background `wl-copy`/`xclip`/`xsel` process that keeps serving the clipboard was suspended along with pi ([#11179](https://github.com/earendil-works/pi/issues/11179))
## [1.3.0] - 2026-10-15

View file

@ -8,8 +8,11 @@ export function runClipboardCommand(
): Promise<Buffer | undefined> {
return new Promise((resolve) => {
// Clipboard writers can daemonize. Do not give them output pipes to retain.
// Detach on POSIX so the daemon leaves pi's process group and Ctrl+Z suspend
// (SIGTSTP to the group) does not stop the clipboard owner (#11179).
const child = spawn(command, args, {
stdio: ["pipe", options?.input === undefined ? "pipe" : "ignore", "ignore"],
detached: process.platform !== "win32",
windowsHide: true,
});
const chunks: Buffer[] = [];

View file

@ -29,6 +29,16 @@ describe("clipboard commands", () => {
clearInterval(timer);
}
});
// #11179: clipboard daemons must not share pi's process group, or Ctrl+Z suspend stops them.
test.skipIf(process.platform === "win32")("runs commands outside pi's process group", async () => {
const childPgid = (await runClipboardCommand("sh", ["-c", "ps -o pgid= -p $$"]))?.toString("utf8").trim();
const ownPgid = (await runClipboardCommand("ps", ["-o", "pgid=", "-p", String(process.pid)]))
?.toString("utf8")
.trim();
expect(childPgid).toMatch(/^\d+$/);
expect(ownPgid).toMatch(/^\d+$/);
expect(childPgid).not.toBe(ownPgid);
});
test("rejects output above the buffer limit", async () => {
expect(
await runClipboardCommand(process.execPath, ["-e", "process.stdout.write(Buffer.alloc(1024))"], {