4 Commits
Author SHA1 Message Date
clawbot aeb275e137 README: the close() sentence split in two (closes #231)
check / check (push) Waiting to run
The sentence in "Opening a library" had a relative clause with its
"that" left out, so "returns resolves" read as two verbs in a row. It
is now two sentences; the behaviour described is unchanged and matches
`close()` in `src/library/index.ts`.

Model: fable-5-1 (change); opus-5-5 (landing message)
2026-10-26 19:32:03 +01:00
clawbot 67794bf5f8 README: four sentences fixed for the documents gate (closes #229)
check / check (push) Waiting to run
The documents gate on `next` failed five README sentences
(#219 (comment)). Four
are rewritten after a check against the code:

- the keywords score sentence is split in two;
- `mlData` drops the whole `clip` block, as `src/backup.ts` and
  `src/metadata-backup.ts` do;
- a file name gets its ID past 255 bytes and a collection name past
  250, and either is then cut short, as `uniqueNames` does;
- `lastTriedAt` is taken once per run, after its refresh.

The IDs sentence keeps `-1`: the pinned option parser passes a negative
number to a command with no subcommands as an argument, so
`quak get -1` reaches the ID check. Nothing else changes; `make fmt`
reflowed the touched paragraphs.

Model: fable-5-1 (change); opus-5-5 (landing message)
2026-10-26 18:59:28 +01:00
clawbot b5fcbf4400 README.md rewritten sentence by sentence (closes #219)
check / check (push) Waiting to run
The old text served as the list of what to cover. The new text leads
with what quak is, what it is for and how to use it. Every command,
option, exit code and file layout follows in reference sections, then the
library reference, then design, entrypoints and development. Every
statement was checked against the code on next; the pull request lists
each disagreement. Sentences stay under about 30 words, tables are lists,
and no issue links or project history remain in text for users. Two code
comments now name the new README sections, and the one in
`src/cli-log.ts` matches "What quak prints" on stderr, stdout and exit
status; a third no longer cites the README.

Model: fable-5-1
2026-10-26 17:48:25 +01:00
clawbot a1ea47f9a8 quak helper fix-missing-thumbnails --file on an empty cache stops fetching collections once it finds every file (closes #223)
check / check (push) Waiting to run
`helper fix-missing-thumbnails --file` used to wait for a refresh, which
on an empty cache fetched the files of every collection. It now finds the
named files through the new `freshFilesByID` in `src/cli-read.ts`, by the
rule `freshFile` follows. On an empty cache it reads the collection list,
then one collection's files at a time, and stores none of the collections
or file records it reads. It searches the most recently updated
collection first. So a file in several albums is still named after the
first of them that `Library.albums.list()` lists. `fixMissingThumbnails`
now takes the records the command found, and fetches each original
through `lib.originalOf()`.

Model: opus-5-5
2026-10-26 11:25:10 +01:00
5 changed files with 1740 additions and 1242 deletions
+1711 -1233
View File
File diff suppressed because it is too large Load Diff
+10 -7
View File
@@ -1,15 +1,18 @@
// The CLI's log level, and the one function the commands write stderr lines
// through.
//
// Every line quak prints on stderr is a log line at one of six levels, from
// the quietest: fatal, error, warning, info, debug, trace. A run prints the
// lines at its own level and at every quieter one. Its level is info unless
// `-v` or `-q` asks for another (see "CLI surface" in the README). Every
// command that exits non-zero logs a fatal line saying why, so even `-q`, which
// prints only fatal lines, never leaves a non-zero exit unexplained. An error
// Every line quak logs goes to stderr, at one of six levels, from the
// quietest: fatal, error, warning, info, debug, trace. A run prints the lines
// at its own level and at every quieter one. Its level is info unless `-v` or
// `-q` asks for another (see "What quak prints" in the README). A command that
// runs and exits non-zero logs a fatal line saying why, so even `-q`, which
// prints only fatal lines, never leaves such an exit unexplained. An error
// line reports something that failed, such as a file or an album, and a
// warning something that did not fail but needs the user's attention. stdout
// carries only a command's output and is not a log.
// carries a command's output and the prompts of `login`, and is not a log.
// Two things on stderr are not log lines: the `error:` message for a
// command line that quak cannot parse, and the usage printed when no command
// is given.
//
// The library itself writes no lines: its layers report through callbacks, and
// the CLI logs what they report. `logRequests` gives the API client options
+1 -1
View File
@@ -418,7 +418,7 @@ describe("the first backup of the account", () => {
expect(downloads.sort()).toEqual([100, 200, 300]);
});
// The tree "Backup layout" in the README describes. Each original is at
// The tree under "The backup directory" in the README. Each original is at
// its save path, `YYYY/YYYY-MM/YYYY-MM-DD/YYYY-MM-DD.<fileID>.<ext>`, with
// the extension of its title; the live photo is its image and its video,
// each with the extension it had inside the ZIP, and a `.livephoto.json`
+1 -1
View File
@@ -328,7 +328,7 @@ describe("what the library reports", () => {
]);
});
// Each operation is named in plain words, as the README names it.
// Each operation is named in plain words.
it("logs a refresh's progress at info, and its start and end at debug", () => {
const { log, lines } = collect();
const onProgress = logRefresh(log);
+17
View File
@@ -284,6 +284,23 @@ describe("CLI read helpers (issue #36 amendment, issue #52)", () => {
expect(found.get(20)?.collection.id).toBe(2);
});
// Collection 1 was updated last, though collections 2 and 3 have higher
// IDs. File 11 is in collections 1 and 2.
it("freshFilesByID on an empty cache reads the most recently updated collection first, though its ID is the lowest", async () => {
const lib = new FakeLibrary(
[collection(1, 400), collection(2, 200), collection(3, 300)],
[
file(11, 1, 1_700_000_000_000_001),
file(11, 2, 1_700_000_000_000_001),
],
);
const found = await freshFilesByID(lib, [11]);
expect(lib.freshFilesCalls).toEqual([1]);
expect(found.get(11)?.collection.id).toBe(1);
expect(found.get(11)?.file.collectionID).toBe(1);
});
// The stand-in's cache holds what the server holds once `fresh()` has run.
it("freshFilesByID on a cache that holds the collections refreshes, then finds each file in the most recently updated collection that holds it", async () => {
const lib = fileInTwoCollections();