Merge PR #8704: fix(cli): exit cleanly after printing shell completions (@czchen)

This commit is contained in:
can1357
2026-08-19 01:36:03 +02:00
3 changed files with 26 additions and 1 deletions
+3
View File
@@ -25,6 +25,9 @@
### Fixed
- Fixed `omp stats` and `/stats` dashboards being unreachable from container hosts by accepting an explicit `--host` bind address while preserving the `127.0.0.1` default.
### Fixed
- Fixed `omp completions <shell>` hanging after writing shell completion scripts to stdout by invoking `postmortem.quit(0)` upon completion. Prevents lingering event loop handles (such as background timers or sockets loaded when inspecting command metadata) from pinning the process and blocking tools like `chezmoi`.
## [17.3.5] - 2026-08-16
@@ -5,7 +5,7 @@
* (see `cli/completion-gen.ts`), so it never drifts from the actual CLI surface.
*/
import { APP_NAME, VERSION } from "@oh-my-pi/pi-utils";
import { APP_NAME, postmortem, VERSION } from "@oh-my-pi/pi-utils";
import { Args, type CliConfig, Command, type CommandCtor } from "@oh-my-pi/pi-utils/cli";
import { completionsHelp as commandHelp } from "../cli/command-help";
import { buildSpec, generateCompletion, type Shell } from "../cli/completion-gen";
@@ -55,6 +55,7 @@ export default class Completions extends Command {
}
await Bun.write(Bun.stdout, await generateLiveCompletion(shell));
await postmortem.quit(0);
}
}
@@ -0,0 +1,21 @@
import { afterEach, describe, expect, it, spyOn } from "bun:test";
import { postmortem } from "@oh-my-pi/pi-utils";
import Completions from "../src/commands/completions";
describe("Completions command exit contract", () => {
afterEach(() => {
spyOn(postmortem, "quit").mockRestore();
spyOn(Bun, "write").mockRestore();
});
it("calls postmortem.quit(0) after writing completion script", async () => {
const quitSpy = spyOn(postmortem, "quit").mockResolvedValue(undefined);
const writeSpy = spyOn(Bun, "write").mockResolvedValue(0);
const config = { bin: "omp", version: "0.0.0", commands: new Map() };
const cmd = new Completions(["zsh"], config);
await cmd.run();
expect(writeSpy).toHaveBeenCalled();
expect(quitSpy).toHaveBeenCalledWith(0);
});
});