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

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
+26 -3
View File
@@ -544,11 +544,22 @@ describe("listMissingThumbnails", () => {
const client = await login(counted.fetch, { ...noWait });
const lib = await openLib(client);
const missing = await listMissingThumbnails(lib, client);
const errors: string[] = [];
const missing = await listMissingThumbnails(
lib,
client,
(msg, level) => {
if (level === "error") errors.push(msg);
},
);
lib.close();
// Only the genuinely empty thumbnail is reported.
// Only the genuinely empty thumbnail is reported. The file that
// could not be checked is reported as an error.
expect(missing.map((m) => m.fileID)).toEqual([101]);
expect(errors).toEqual([
expect.stringMatching(/^\[.*\] Could not check file-102\.jpg: /),
]);
// And the 500 was retried rather than accepted as an answer: four
// attempts is the library default.
expect(counted.matched()).toBe(4);
@@ -699,7 +710,15 @@ describe("fixMissingThumbnails", () => {
const client = await login(buildThumbFetch(fixMock));
const lib = await openLib(client);
const results = await fixMissingThumbnails(lib, client, [101, 102]);
const errors: string[] = [];
const results = await fixMissingThumbnails(
lib,
client,
[101, 102],
(msg, level) => {
if (level === "error") errors.push(msg);
},
);
lib.close();
expect(results.length).toBe(2);
@@ -707,6 +726,10 @@ describe("fixMissingThumbnails", () => {
const failure = results.find((r) => r.fileID === 102)!;
expect(success.status).toBe("fixed");
expect(failure.status).toBe("failed");
// The failed file, and only it, is reported as an error.
expect(errors).toEqual([
expect.stringMatching(/^\[.*\] FAILED file-102\.jpg: /),
]);
});
it("skips a non-JPEG image and a video as unsupported, not failed (issue #17)", async () => {