-v raises the CLI's log level per repeat; -q prints only fatal errors (closes #212)
check / check (push) Canceled after 0s

Every line quak prints on stderr now goes through one log, in src/cli-log.ts, at one of six levels. The default, info, prints what quak printed before. -v adds each retry and the start and end of each refresh and ML data fetch; -vv adds each request with its result. -q prints only fatal lines, and is refused with -v; both are program options. Every non-zero exit logs one fatal line, so a run that exits 1 because files failed says how many and where to look. Every line reporting a failure is at error. --json changes stdout only, so backup and --json runs log their progress on stderr. withRetry and ApiClient report retries and requests through new callbacks.

Model: opus-5-5
This commit was merged in pull request #216.
This commit is contained in:
2026-10-18 21:46:59 +02:00
parent 92e0c6c791
commit 68d22b9927
21 changed files with 1099 additions and 188 deletions
+12 -9
View File
@@ -2,21 +2,23 @@
import type { Writable } from "node:stream";
import { ApiError } from "./api/client.js";
import type { Log } from "./cli-log.js";
import { describeError } from "./errors.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. MESSAGE is the error as `describeError` gives
// it, so it carries the reason Node's `fetch` puts on `cause`. 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.
// An error the command throws is logged as one fatal `quak: MESSAGE` line,
// without the stack trace, and exits 1. MESSAGE is the error as
// `describeError` gives it, so it carries the reason Node's `fetch` puts on
// `cause`. A 401 from the server means it no longer accepts the saved session:
// that logs one fatal 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,
log: Log,
exit: (code: number) => void,
): Promise<void> => {
let code: number;
@@ -24,12 +26,13 @@ export const run = async (
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`,
log(
"fatal",
`quak: the saved session is no longer valid; run "quak login"`,
);
code = 3;
} else {
stderr.write(`quak: ${describeError(err)}\n`);
log("fatal", `quak: ${describeError(err)}`);
code = 1;
}
}