Compare commits

..
1 Commits
Author SHA1 Message Date
sneak 1283048ce2 An expired session exits 3 with one line saying to run quak login (closes #164)
check / check (push) Successful in 2m20s
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
2026-10-06 01:21:30 +00:00
2 changed files with 25 additions and 12 deletions
+11 -8
View File
@@ -516,14 +516,17 @@ The CLI stores the snapshot at the platform-appropriate data directory via
`0600`. The key material is stored in cleartext in the JSON; treat this file as
you would treat the password itself. A missing file is reported as "not logged
in"; a file that exists but is corrupt is reported as such, naming the bad
field. When the server answers a command's request with HTTP 401, because it no
longer accepts the saved session's token, the command prints one line,
`quak: the saved session is no longer valid; run "quak login"`, with no stack
trace. All three exit with status 3, which means the user must run `quak login`
again. `quak logout` is the exception: with no file it says there is no session
and exits 0, and it handles a corrupt file or a failed server call as described
below. `quak backup` meets an expired session on the refresh that starts every
run, before it touches any file. No command but `quak login` ever prompts.
field. When the refresh a command starts with gets HTTP 401 from the server,
because it no longer accepts the saved session's token, the command prints one
line, `quak: the saved session is no longer valid; run "quak login"`, with no
stack trace. All three exit with status 3, which means the user must run
`quak login` again. `quak logout` is the exception: with no file it says there
is no session and exits 0, and it handles a corrupt file or a failed server call
as described below. `quak backup` meets an expired session on the refresh that
starts every run, before it touches any file. A session that stops working
partway through a backup instead fails each remaining file into `failures.json`,
so that run exits 1 and the next one stops at its refresh with status 3. No
command but `quak login` ever prompts.
`quak logout` ends the session on the server, so the token in `session.json`
stops working even in a copy of the file, and then deletes the file. If the
+14 -4
View File
@@ -230,14 +230,24 @@ describe("session file", () => {
expect(JSON.parse(readFileSync(path, "utf-8"))).toEqual(snapshot);
});
it("a missing session exits 3 with 'Not logged in'", async () => {
it("a missing session exits 3 with 'Not logged in' from every command that needs one", async () => {
const ctx = { ...context(), loadSession };
const dir = join(root, "backup");
expect(await whoamiCommand(ctx)).toBe(3);
expect(stderr.text).toBe(
expect(await collectionsCommand(ctx, {})).toBe(3);
expect(await filesCommand(ctx, { collection: "1" })).toBe(3);
expect(await getCommand(ctx, "100", {})).toBe(3);
expect(await getThumbCommand(ctx, "100", {})).toBe(3);
expect(await backupMetadataCommand(ctx, dir, {})).toBe(3);
expect(await backupCommand(ctx, dir, {})).toBe(3);
expect(await listMissingThumbnailsCommand(ctx, {})).toBe(3);
expect(await fixMissingThumbnailsCommand(ctx, {})).toBe(3);
const notLoggedIn =
`Not logged in. Run "quak login" first.\n` +
`Session file: ${join(ctx.sessionDir, "session.json")}\n`,
);
`Session file: ${join(ctx.sessionDir, "session.json")}\n`;
expect(stderr.text).toBe(notLoggedIn.repeat(9));
expect(stdout.text).toBe("");
expect(existsSync(dir)).toBe(false);
});
it("a corrupt session exits 3 and says it is corrupt", async () => {