check / check (push) Failing after 2s
A 401 from the server reaches run in src/cli-run.ts as the ApiError the refresh threw, so run recognises it there, prints one line saying to run "quak login" and exits 3. A missing or corrupt session file keeps its message and also exits 3. quak backup meets the 401 on its first refresh, before it touches any file. Every other error still exits 1. Judgement call: quak logout is unchanged; it handles its own errors and deletes the session file whatever the server answers. Judgement call: quak backup still prints its two progress lines before the error line. Model: opus-5-5
47 lines
1.6 KiB
TypeScript
47 lines
1.6 KiB
TypeScript
// Runs one CLI command for `bin/quak.ts` and exits with its code.
|
|
|
|
import type { Writable } from "node:stream";
|
|
import { ApiError } from "./api/client.js";
|
|
|
|
// Run a command and exit with its code once stdout/stderr have drained.
|
|
// Exiting before the drain can truncate piped output, and the library can keep
|
|
// the event loop alive after a command returns, so a plain return could hang.
|
|
// An error the command throws is printed as one `quak: MESSAGE` line, without
|
|
// the stack trace, and exits 1. A 401 from the server means it no longer
|
|
// accepts the saved session: that prints one line saying to log in again and
|
|
// exits 3, as a missing or corrupt session file does.
|
|
export const run = async (
|
|
command: Promise<number>,
|
|
stdout: Writable,
|
|
stderr: Writable,
|
|
exit: (code: number) => void,
|
|
): Promise<void> => {
|
|
let code: number;
|
|
try {
|
|
code = await command;
|
|
} catch (err) {
|
|
if (err instanceof ApiError && err.status === 401) {
|
|
stderr.write(
|
|
`quak: the saved session is no longer valid; run "quak login"\n`,
|
|
);
|
|
code = 3;
|
|
} else {
|
|
stderr.write(
|
|
`quak: ${err instanceof Error ? err.message : String(err)}\n`,
|
|
);
|
|
code = 1;
|
|
}
|
|
}
|
|
const pending = [stdout, stderr].filter((s) => s.writableLength > 0);
|
|
if (pending.length === 0) {
|
|
exit(code);
|
|
return;
|
|
}
|
|
let remaining = pending.length;
|
|
for (const s of pending) {
|
|
s.once("drain", () => {
|
|
if (--remaining === 0) exit(code);
|
|
});
|
|
}
|
|
};
|