All checks were successful
check / check (push) Successful in 1m2s
Linting now happens in one place only: a new root Dockerfile.lint copies the repo into the digest-pinned node image already used by Dockerfile and runs eslint and prettier as build steps, so a successful build is a clean lint. script/lint is reduced to building it, which also works where the docker daemon is remote and bind mounts are impossible. No host lint path survives: the "lint" script is gone from package.json, so there is no second, unpinned way to get a lint verdict. Caching is waived for lint, because a lint build over an unchanged tree returns success in well under a second having linted nothing. LINT_EPOCH is the cache buster and it fails closed exactly as CHECK_EPOCH does: an unset ARG is the empty string, which is a perfectly stable cache key, so the guard rejects it and a bare `docker build -f Dockerfile.lint .` errors out instead of serving a green it did not earn. Both linters sit below the guard, so a fresh epoch forces them to execute while the bootstrap and dependency layers above stay cached. That makes script/lint a docker build, which nothing inside a container may call. script/check calls script/lint, so the Dockerfile image can no longer run make check: the lint stage and its COPY --from=lint ordering hack are deleted, and the remaining stage runs make test and make build under the existing CHECK_EPOCH guard. script/cibuild is now the composite gate and builds the lint image first, so a lint failure is reported before the slower suite runs. The .dockerignore exclusions are unchanged and still apply to the lint build, including the .claude/ exclusion (eslint's flat config does not ignore dot-directories, so a nested worktree in the context would be linted) and the deliberate exception that keeps .gitignore in the context for prettier. A new test asserts no per-Dockerfile ignore file shadows the root one for either image, and test/packaging/lint-docker.test.ts asserts the whole shape: the docker-only lint path, the digest pin, manifests copied before sources, the fail-closed guard with both linters below it, the absence of a lint stage or make check in Dockerfile, and the build order in script/cibuild.
4.5 KiB
4.5 KiB
Workflow
- branch (from
main) - do the work in Next Step
- move Next Step to the top of Completed Steps
- move the top item of Future Steps into Next Step
- commit (
TODO.mdchanges in the same commit as the work) - merge to
mainif the branch is not protected, otherwise open a PR - push
Status
pre-1.0
Next Step
Update the README API reference section to match the current implementation.
Completed Steps
- 2026-08-10: Moved all linting into Docker.
script/lintbuilds a new rootDockerfile.lint, which copies the repo into the digest-pinned node image and runs eslint and prettier as build steps, so a successful build is a clean lint; no host lint path remains andyarn lintis gone frompackage.json. A fail-closedLINT_EPOCHguard stops Docker serving the linter layers from cache, which is how a lint build returns success in under a second having linted nothing. The lint stage insideDockerfileand itsCOPY --from=lintordering hack are gone: that image now runsmake testandmake buildonly, becausescript/checkcallsscript/lintand running it in a container would mean docker inside docker.script/cibuildbuilds the lint image first, then the test and build image. - 2026-08-09: Made
make dockergreen and policy-conformant. Multi-stage Dockerfile: a lint stage runsmake fmt-checkandmake lint, and the check stage takes aCOPY --from=lintdependency on it before runningmake checkandmake build.CHECK_EPOCHand a fail-closed guard stop Docker serving those two layers from cache, which is what let a build report success without running the suite.script/projectnamesaysquak, so the image is taggedquak;script/bootstrapupdates apt lists before installing, so a Debian base works;.dockerignoreno longer ships the compiled binary, the caches or agent worktrees into the build context, and keeps.gitignorein it for prettier. - 2026-08-09: Fixed the TypeScript build.
rootDiris the repo root, sobin/compiles alongsidesrc/instead of failing with TS6059; output isdist/src/anddist/bin/, which is wheremain,typesandbin.quaknow point.script/buildverifies the declared entrypoints exist after the compiler runs and makes the CLI executable, the Dockerfile runsmake buildas well asmake check, and aquakscript makes the README'syarn quak <command>examples work. - 2026-08-09: Retry policy: no retry on 4xx (except
408and429), exponential backoff with full jitter on 5xx, transport failures and truncated transfers, under per-attempt deadlines that cover the response body as well as the request. Downloads retry request, stream consumption and decryption as one unit;postJSONandputJSONare replayed only when the connection was never established. - 2026-08-09: Downloads verify the secretstream terminated on
TAG_FINALand write output atomically: a truncated body is rejected instead of landing on disk as a short file, and plaintext is staged in a sibling temp file and renamed into place, so a failed download leaves the destination untouched. - 2026-07-07 Adopted scripts-to-rule-them-all:
script/entrypoints, Makefile shims, README Entrypoints section - 2026-06-10: Decrypted collections shared by other users (sealed-box keys); listCollections drops deleted-collection tombstones.
- 2026-06-10: Login hardening: dual-2FA empty-string fields handled, TOTP preferred when a passkey is also enrolled, interactive input via @inquirer/prompts.
- 2026-06-10: Replaced sharp with pure JS (jpeg-js + exif-reader); added single-binary bun build and make install.
- 2026-06-09: Added backup-metadata command (ML data always included, --exif opt-in); rewrote README to match the implementation; added thumbnail helper tests.
- 2026-05-13: Full CLI surface: login, backup with dedup symlink layout, collections, files, get, get-thumb, thumbnail repair helpers.
- 2026-05-13: Client OO API with literate usage tests; file download and decryption; all three metadata layers decrypted and persisted; renamed quack to quak.
- 2026-05-11: SRP login flow (email OTP + TOTP) and ApiClient.
Future Steps
- Tag v1.0.0.
- Future desktop client, separate repo:
- Electron app skeleton consuming this library.
- Local SQLite cache keyed on (collectionID, fileID, updationTime).
- Background sync worker streaming new files into the cache.
- Gallery UI: thumbnails, full-image view, basic search.
- Upload, delete, and share operations in the library.