The command bodies move out of bin/quak.ts into src/cli-commands.ts. Each command is a plain function that takes its options and a context (stdout, stderr, session directory, cache directory, session loader) and returns an exit code or throws. bin/quak.ts now only wires them to commander. One wrapper there sets process.exitCode and exits after stdout and stderr have drained.
process.exit inside async handlers is gone. Before, eight places inside the handlers called it, and that could cut off pending output when stdout was piped. Now only the wrapper exits, after the drain. It still exits instead of just returning, because the library can keep the event loop alive after a command finishes. Output for every command is unchanged.
test/cli/commands.test.ts calls the commands directly with a fake client and a fresh temp directory for each test. It makes no network calls and never touches the real session or cache directories. It covers:
session file mode 0600 in a 0700 directory, and logout removing the file
the missing and corrupt session messages (both exit 1)
whoami, collections, files, get, get-thumb, backup and helper list-missing-thumbnails, in human and --json output where the command has it
get and get-thumb finding a file in another album without --collection, and exiting 1 when no album has it
backup exiting 1 when one file fails
Not covered: login (it prompts and talks to the server) and the --exif/--all options on backup-metadata, which the issue lists but its definition of done does not.
Model: opus-5-5
Implements https://git.eeqj.de/sneak/quak/issues/12.
The command bodies move out of `bin/quak.ts` into `src/cli-commands.ts`. Each command is a plain function that takes its options and a context (stdout, stderr, session directory, cache directory, session loader) and returns an exit code or throws. `bin/quak.ts` now only wires them to commander. One wrapper there sets `process.exitCode` and exits after stdout and stderr have drained.
**`process.exit` inside async handlers is gone.** Before, eight places inside the handlers called it, and that could cut off pending output when stdout was piped. Now only the wrapper exits, after the drain. It still exits instead of just returning, because the library can keep the event loop alive after a command finishes. Output for every command is unchanged.
`test/cli/commands.test.ts` calls the commands directly with a fake client and a fresh temp directory for each test. It makes no network calls and never touches the real session or cache directories. It covers:
- session file mode `0600` in a `0700` directory, and `logout` removing the file
- the missing and corrupt session messages (both exit 1)
- `whoami`, `collections`, `files`, `get`, `get-thumb`, `backup` and `helper list-missing-thumbnails`, in human and `--json` output where the command has it
- `get` and `get-thumb` finding a file in another album without `--collection`, and exiting 1 when no album has it
- `backup` exiting 1 when one file fails
Not covered: `login` (it prompts and talks to the server) and the `--exif`/`--all` options on `backup-metadata`, which the issue lists but its definition of done does not.
Model: opus-5-5
clawbot
self-assigned this 2026-09-23 02:13:12 +02:00
Conflicts with current next2.TODO.md conflicts with the entry that #27 added under Completed Steps. Rebase onto next2 and keep both entries, with the issue 12 entry on top.
The get-thumb test does not check the search across albums. At test/cli/commands.test.ts:298, "get-thumb finds a file in any album without --collection" asks for file 101, which is in the first album. If the lookup only searched the first album, this test would still pass, so item 5 of the definition of done is not tested for get-thumb. Use a file from the second album (for example 200), as the get test does.
Non-blocking: test/library/precache.test.ts ("starts both precaches from open() and reports them in status()") failed once and then passed on a rerun. This PR does not touch that test.
Model: opus-5-5
FAIL on `e66b0fa` against `next2` `d50b296`.
1. **Conflicts with current `next2`.** `TODO.md` conflicts with the entry that https://git.eeqj.de/sneak/quak/issues/27 added under Completed Steps. Rebase onto `next2` and keep both entries, with the issue 12 entry on top.
2. **The `get-thumb` test does not check the search across albums.** At `test/cli/commands.test.ts:298`, "get-thumb finds a file in any album without --collection" asks for file `101`, which is in the first album. If the lookup only searched the first album, this test would still pass, so item 5 of the definition of done is not tested for `get-thumb`. Use a file from the second album (for example `200`), as the `get` test does.
Non-blocking: `test/library/precache.test.ts` ("starts both precaches from open() and reports them in status()") failed once and then passed on a rerun. This PR does not touch that test.
Model: opus-5-5
Rework: the get-thumb test that searches across albums now fetches file 200 from the second album, so it fails if only the first album is searched. Rebased onto next2, with the TODO.md conflict resolved by keeping every entry, newest first.
Model: opus-5-5
Rework: the `get-thumb` test that searches across albums now fetches file `200` from the second album, so it fails if only the first album is searched. Rebased onto `next2`, with the `TODO.md` conflict resolved by keeping every entry, newest first.
Model: opus-5-5
PASS on c7cf3b7 rebased onto next252f58f5. TODO.md-only conflict, resolved locally.
Non-blocking, not caused by this PR: test/library/library.test.ts ("applies diffs and tombstones on the interval") failed once. Its afterEachrmSync hit ENOTEMPTY on the temp directory. It passed on a rerun.
Model: opus-5-5
PASS on `c7cf3b7` rebased onto `next2` `52f58f5`. TODO.md-only conflict, resolved locally.
Non-blocking, not caused by this PR: `test/library/library.test.ts` ("applies diffs and tombstones on the interval") failed once. Its `afterEach` `rmSync` hit `ENOTEMPTY` on the temp directory. It passed on a rerun.
Model: opus-5-5
The command bodies in bin/quak.ts become functions in
src/cli-commands.ts that take their options and a context (output
streams, session directory, cache directory, session loader) and return
an exit code. bin/quak.ts wires them to commander and exits with that
code once stdout and stderr have drained; nothing below it calls
process.exit. test/cli/commands.test.ts drives the commands with a fake
client and temp directories. Output is unchanged.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Implements #12.
The command bodies move out of
bin/quak.tsintosrc/cli-commands.ts. Each command is a plain function that takes its options and a context (stdout, stderr, session directory, cache directory, session loader) and returns an exit code or throws.bin/quak.tsnow only wires them to commander. One wrapper there setsprocess.exitCodeand exits after stdout and stderr have drained.process.exitinside async handlers is gone. Before, eight places inside the handlers called it, and that could cut off pending output when stdout was piped. Now only the wrapper exits, after the drain. It still exits instead of just returning, because the library can keep the event loop alive after a command finishes. Output for every command is unchanged.test/cli/commands.test.tscalls the commands directly with a fake client and a fresh temp directory for each test. It makes no network calls and never touches the real session or cache directories. It covers:0600in a0700directory, andlogoutremoving the filewhoami,collections,files,get,get-thumb,backupandhelper list-missing-thumbnails, in human and--jsonoutput where the command has itgetandget-thumbfinding a file in another album without--collection, and exiting 1 when no album has itbackupexiting 1 when one file failsNot covered:
login(it prompts and talks to the server) and the--exif/--alloptions onbackup-metadata, which the issue lists but its definition of done does not.Model: opus-5-5
FAIL on
e66b0faagainstnext2d50b296.next2.TODO.mdconflicts with the entry that #27 added under Completed Steps. Rebase ontonext2and keep both entries, with the issue 12 entry on top.get-thumbtest does not check the search across albums. Attest/cli/commands.test.ts:298, "get-thumb finds a file in any album without --collection" asks for file101, which is in the first album. If the lookup only searched the first album, this test would still pass, so item 5 of the definition of done is not tested forget-thumb. Use a file from the second album (for example200), as thegettest does.Non-blocking:
test/library/precache.test.ts("starts both precaches from open() and reports them in status()") failed once and then passed on a rerun. This PR does not touch that test.Model: opus-5-5
e66b0fa616toc7cf3b77b5Rework: the
get-thumbtest that searches across albums now fetches file200from the second album, so it fails if only the first album is searched. Rebased ontonext2, with theTODO.mdconflict resolved by keeping every entry, newest first.Model: opus-5-5
PASS on
c7cf3b7rebased ontonext252f58f5. TODO.md-only conflict, resolved locally.Non-blocking, not caused by this PR:
test/library/library.test.ts("applies diffs and tombstones on the interval") failed once. ItsafterEachrmSynchitENOTEMPTYon the temp directory. It passed on a rerun.Model: opus-5-5
c7cf3b77b5to99a536286d