error TS6059: File '/…/quak/bin/quak.ts' is not under 'rootDir' '/…/quak/src'.
'rootDir' is expected to contain all source files.
tsconfig.json:8 sets "rootDir": "./src" while tsconfig.json:20 sets "include": ["src/**/*", "bin/**/*"]. The two contradict each other.
Nothing catches this: make check runs test, lint and fmt-check only (script/check), and
the Dockerfile runs make check but never make build. So a repo whose package.json
declares "main": "./dist/index.js" and "bin": {"quak": "./dist/bin/quak.js"} cannot
produce either artifact, and CI is blind to it.
The README's Getting Started block also tells users to run yarn quak login, yarn quak collections, etc. There is no quak script in package.json, so every one of those
commands fails.
Definition of done
make build succeeds from a clean checkout and emits JavaScript plus declaration files
under dist/.
package.jsonmain, types and bin point at paths that the build actually produces,
verified by inspecting dist/ after a build.
The emitted CLI entrypoint retains the #!/usr/bin/env node shebang from bin/quak.ts:1
and is executable.
yarn quak <command> works after yarn build, matching what the README's Getting Started
section already promises — add the missing quak script to package.json.
The Dockerfile runs make build in addition to make check, so this class of error can
never reach main again. (Do not change what make check itself runs — the repo policy
fixes its composition as test + lint + fmt-check.)
make clean still removes everything the build produces.
make check green.
TODO.md updated in the same commit.
Recommended approach
Set "rootDir": "." and update package.jsonmain/types/bin to the resulting dist/src/… and dist/bin/… paths. This is the smallest change and keeps the source layout
the README documents.
The alternative — moving the CLI body into src/cli.ts and leaving a thin shim in bin/ —
keeps dist/index.js as the package main but churns more files and contradicts the layout
diagram in the README's Design section. Pick the first unless you find a concrete reason not
to, and record the reasoning in the PR body.
Out of scope
engines, exports, and prepublishOnly — tracked separately.
## Problem
`make build` is **broken on `main` right now**:
```
error TS6059: File '/…/quak/bin/quak.ts' is not under 'rootDir' '/…/quak/src'.
'rootDir' is expected to contain all source files.
```
`tsconfig.json:8` sets `"rootDir": "./src"` while `tsconfig.json:20` sets
`"include": ["src/**/*", "bin/**/*"]`. The two contradict each other.
Nothing catches this: `make check` runs test, lint and fmt-check only (`script/check`), and
the Dockerfile runs `make check` but never `make build`. So a repo whose `package.json`
declares `"main": "./dist/index.js"` and `"bin": {"quak": "./dist/bin/quak.js"}` cannot
produce either artifact, and CI is blind to it.
The README's Getting Started block also tells users to run `yarn quak login`, `yarn quak
collections`, etc. There is no `quak` script in `package.json`, so every one of those
commands fails.
## Definition of done
1. `make build` succeeds from a clean checkout and emits JavaScript plus declaration files
under `dist/`.
2. `package.json` `main`, `types` and `bin` point at paths that the build actually produces,
verified by inspecting `dist/` after a build.
3. The emitted CLI entrypoint retains the `#!/usr/bin/env node` shebang from `bin/quak.ts:1`
and is executable.
4. `yarn quak <command>` works after `yarn build`, matching what the README's Getting Started
section already promises — add the missing `quak` script to `package.json`.
5. The Dockerfile runs `make build` in addition to `make check`, so this class of error can
never reach `main` again. (Do not change what `make check` itself runs — the repo policy
fixes its composition as test + lint + fmt-check.)
6. `make clean` still removes everything the build produces.
7. `make check` green.
8. `TODO.md` updated in the same commit.
## Recommended approach
Set `"rootDir": "."` and update `package.json` `main`/`types`/`bin` to the resulting
`dist/src/…` and `dist/bin/…` paths. This is the smallest change and keeps the source layout
the README documents.
The alternative — moving the CLI body into `src/cli.ts` and leaving a thin shim in `bin/` —
keeps `dist/index.js` as the package main but churns more files and contradicts the layout
diagram in the README's Design section. Pick the first unless you find a concrete reason not
to, and record the reasoning in the PR body.
## Out of scope
`engines`, `exports`, and `prepublishOnly` — tracked separately.
clawbot
added this to the 1.0.0 milestone 2026-08-09 03:43:28 +02:00
clawbot
self-assigned this 2026-08-09 03:43:28 +02:00
Written against main at 348f23b, after #1 and #2 landed. make check is green there (18 test
files, 210 tests, ~10s); make build is not.
The contradiction
tsconfig.json sets "rootDir": "./src" and "include": ["src/**/*", "bin/**/*"]. Those cannot
both hold — bin/quak.ts is outside rootDir, hence TS6059. Reproduce it first via make build
so you have the exact message in front of you before changing anything.
Nothing catches this today: script/check runs test, lint and fmt-check only, and the Dockerfile
runs make check but never make build. That is why a repo declaring "main": "./dist/index.js"
and "bin": {"quak": "./dist/bin/quak.js"} has been unable to produce either artifact.
Take the recommended approach unless you find a real obstacle
Set "rootDir": ".". Emitted layout becomes dist/src/… and dist/bin/…, so update package.json:
main → ./dist/src/index.js
types → ./dist/src/index.d.ts
bin.quak → ./dist/bin/quak.js
The alternative — moving the CLI body into src/ with a thin shim in bin/ — keeps dist/index.js as the package main but churns more files and contradicts the layout diagram in
the README's Design section. If you take it instead, justify it in the PR body with the specific
obstacle you hit.
Either way, resolveJsonModule is already on, and #5 (single-sourcing the version from package.json) will need to import it from the built output — so whatever layout you pick, make
sure a relative import of package.json would resolve from both src/ under vitest and from dist/ after a build. You do not have to implement #5 here, but do not pick a layout that makes
it impossible.
Verify the artifacts exist rather than assuming tsc emitted them
After make build, confirm on disk:
the file each of main, types and bin.quak points at actually exists;
the emitted CLI retains the #!/usr/bin/env node shebang from bin/quak.ts:1;
.d.ts and .js.map files are present for the library entrypoint.
State the observed paths in the PR body. This repo has failed four reviews on claims that were
not checked; "the build succeeds" is not the same statement as "the declared artifacts exist".
The quak script
The README's Getting Started block tells users to run yarn quak login, yarn quak collections
and so on. There is no quak script in package.json, so every one of those commands fails
today. Add it so the documented commands work after yarn build. If the invocation you add
differs from what the README shows, update the README to match — the two must agree at the end.
Dockerfile
Add make build to the Dockerfile so this class of error cannot reach main again. Do not
change what make check runs — REPO_POLICIES.md fixes its composition as test + lint +
fmt-check, and #4 is separately reworking the Dockerfile into a multi-stage build. Keep your change
minimal and additive so it does not collide with #4.
Note that #4 also documents a script/cibuild cache defect: a bare docker build . can serve RUN make check from cache and exit 0 without running anything. That is #4's to fix, not yours —
but it means you must not treat a fast, green docker build as evidence your build step ran. If
you verify the Docker path at all, do it with docker build --no-cache . scoped to this image. Never run docker builder prune or docker system prune — the BuildKit cache is shared across
every repo on this host and an agent elsewhere already destroyed ~41 GB of it doing exactly that.
make clean
It must still remove everything the build now produces. If the output layout changes, update the
target.
Process
Branch off main. TDD applies as far as it sensibly can here: this is a build-configuration
fix, so if you cannot write a meaningful failing test first, say so explicitly in the PR body
rather than staging a token one. A check that the declared package.json entrypoints exist
after a build is the closest thing to a real regression test and is worth adding.
Verify only via make targets / script/ entrypoints. Never invoke tsc, vitest, eslint, prettier or yarn scripts directly.
make check and make build must both be green at the end. Report the measured make test
time — baseline ~10s at 210 tests, 20s budget, 30s hard cap.
Before measuring anything, confirm no git worktrees exist under .claude/worktrees/ in the
tree you are measuring. Per #25, vitest globs them and silently runs the suite N+1 times; a
polluted run reported 1050 tests where the real number is 210.
Run make fmt. TODO.md and any README change go in the same commit as the implementation.
Commit title ends with (closes #3).
Never mention Claude or Anthropic anywhere. No attribution or co-author trailers.
Do not touch anything belonging to #4, #5, #6, #13, #24 or #25.
## Implementation requirements
Written against `main` at `348f23b`, after #1 and #2 landed. `make check` is green there (18 test
files, 210 tests, ~10s); `make build` is not.
### The contradiction
`tsconfig.json` sets `"rootDir": "./src"` and `"include": ["src/**/*", "bin/**/*"]`. Those cannot
both hold — `bin/quak.ts` is outside `rootDir`, hence TS6059. Reproduce it first via `make build`
so you have the exact message in front of you before changing anything.
Nothing catches this today: `script/check` runs test, lint and fmt-check only, and the Dockerfile
runs `make check` but never `make build`. That is why a repo declaring `"main": "./dist/index.js"`
and `"bin": {"quak": "./dist/bin/quak.js"}` has been unable to produce either artifact.
### Take the recommended approach unless you find a real obstacle
Set `"rootDir": "."`. Emitted layout becomes `dist/src/…` and `dist/bin/…`, so update
`package.json`:
- `main` → `./dist/src/index.js`
- `types` → `./dist/src/index.d.ts`
- `bin.quak` → `./dist/bin/quak.js`
The alternative — moving the CLI body into `src/` with a thin shim in `bin/` — keeps
`dist/index.js` as the package main but churns more files and contradicts the layout diagram in
the README's Design section. If you take it instead, justify it in the PR body with the specific
obstacle you hit.
Either way, `resolveJsonModule` is already on, and #5 (single-sourcing the version from
`package.json`) will need to import it from the built output — so whatever layout you pick, make
sure a relative import of `package.json` would resolve from both `src/` under vitest and from
`dist/` after a build. You do not have to implement #5 here, but do not pick a layout that makes
it impossible.
### Verify the artifacts exist rather than assuming tsc emitted them
After `make build`, confirm on disk:
- the file each of `main`, `types` and `bin.quak` points at actually exists;
- the emitted CLI retains the `#!/usr/bin/env node` shebang from `bin/quak.ts:1`;
- `.d.ts` and `.js.map` files are present for the library entrypoint.
State the observed paths in the PR body. This repo has failed four reviews on claims that were
not checked; "the build succeeds" is not the same statement as "the declared artifacts exist".
### The `quak` script
The README's Getting Started block tells users to run `yarn quak login`, `yarn quak collections`
and so on. There is no `quak` script in `package.json`, so every one of those commands fails
today. Add it so the documented commands work after `yarn build`. If the invocation you add
differs from what the README shows, update the README to match — the two must agree at the end.
### Dockerfile
Add `make build` to the Dockerfile so this class of error cannot reach `main` again. Do **not**
change what `make check` runs — `REPO_POLICIES.md` fixes its composition as test + lint +
fmt-check, and #4 is separately reworking the Dockerfile into a multi-stage build. Keep your change
minimal and additive so it does not collide with #4.
Note that #4 also documents a `script/cibuild` cache defect: a bare `docker build .` can serve
`RUN make check` from cache and exit 0 without running anything. That is #4's to fix, not yours —
but it means you must not treat a fast, green `docker build` as evidence your build step ran. If
you verify the Docker path at all, do it with `docker build --no-cache .` scoped to this image.
**Never run `docker builder prune` or `docker system prune`** — the BuildKit cache is shared across
every repo on this host and an agent elsewhere already destroyed ~41 GB of it doing exactly that.
### `make clean`
It must still remove everything the build now produces. If the output layout changes, update the
target.
### Process
- Branch off `main`. TDD applies as far as it sensibly can here: this is a build-configuration
fix, so if you cannot write a meaningful failing test first, say so explicitly in the PR body
rather than staging a token one. A check that the declared `package.json` entrypoints exist
after a build is the closest thing to a real regression test and is worth adding.
- Verify only via `make` targets / `script/` entrypoints. Never invoke `tsc`, `vitest`, `eslint`,
`prettier` or `yarn` scripts directly.
- `make check` and `make build` must both be green at the end. Report the measured `make test`
time — baseline ~10s at 210 tests, 20s budget, 30s hard cap.
- **Before measuring anything, confirm no git worktrees exist under `.claude/worktrees/` in the
tree you are measuring.** Per #25, vitest globs them and silently runs the suite N+1 times; a
polluted run reported 1050 tests where the real number is 210.
- Run `make fmt`. `TODO.md` and any README change go in the same commit as the implementation.
- Commit title ends with ` (closes #3)`.
- Never mention Claude or Anthropic anywhere. No attribution or co-author trailers.
- Do not touch anything belonging to #4, #5, #6, #13, #24 or #25.
Reproduced first, on 348f23b, before touching anything. make bootstrap then make build:
error TS6059: File '/…/bin/quak.ts' is not under 'rootDir' '/…/src'.
'rootDir' is expected to contain all source files.
The file is in the program because:
Matched by include pattern 'bin/**/*' in '/…/tsconfig.json'
Baseline make test in this tree (no worktrees nested under it, checked with git worktree list): 18 files, 210 tests, 7.9s wall.
Plan
Red commit first.test/build/entrypoints.test.ts, asserting the contract that is broken today, without needing a build:
every include pattern in tsconfig.json roots under compilerOptions.rootDir — this is exactly the TS6059 precondition, and it fails at 348f23b;
main, types and bin.quak in package.json equal the paths tsc will emit for src/index.ts and bin/quak.ts given outDir/rootDir;
the quak script invokes the same path as bin.quak;
bin/quak.ts still starts with the #!/usr/bin/env node shebang.
Take the recommended approach:"rootDir": ".". Emitted layout becomes dist/src/… + dist/bin/…; package.json gets main → ./dist/src/index.js, types → ./dist/src/index.d.ts, bin.quak → ./dist/bin/quak.js. This also keeps #5 possible: with rootDir at the repo root, package.json sits inside the root dir, so a relative import of it resolves under both vitest and dist/. I will only deviate to the shim layout if I hit a concrete obstacle, and will say what it was.
script/build (POSIX sh, Makefile build becomes a thin shim per the Scripts to Rule Them All section of REPO_POLICIES.md): run tsc, then verify on disk that each declared entrypoint exists and that the emitted CLI kept its shebang, then chmod +x it. Putting the artifact check in the build rather than in make check keeps make check composition untouched (test + lint + fmt-check) and keeps it independent of a prior build, while still failing loudly in CI. package.json's build script points at script/build so the README's yarn build gets the same guarantees.
quak script in package.json so the README Getting Started commands (yarn quak login, ...) work after yarn build. README stays as-is if the invocation matches; otherwise I update the README.
Dockerfile: add RUN make build after the existing RUN make check — additive only, no change to what make check runs, minimal so it does not collide with #4. I will not run docker builder prune or docker system prune.
make clean already does rm -rf dist, which still covers the new layout; will confirm rather than assume.
make fmt, then make check and make build both green. TODO.md and any README change in the same commit as the implementation; commit title ends with (closes #3).
Verification I will report
The actual ls-observed emitted paths for main, types, bin.quak, the presence of .d.ts/.js.map for the library entrypoint, the observed shebang line and mode bits of the emitted CLI, and the make test count/timing. Nothing goes in the PR body that I did not run in this session.
Out of scope, untouched: engines, exports, prepublishOnly, and anything belonging to #4, #5, #6, #13, #24, #25.
## Implementation plan
Reproduced first, on `348f23b`, before touching anything. `make bootstrap` then `make build`:
```
error TS6059: File '/…/bin/quak.ts' is not under 'rootDir' '/…/src'.
'rootDir' is expected to contain all source files.
The file is in the program because:
Matched by include pattern 'bin/**/*' in '/…/tsconfig.json'
```
Baseline `make test` in this tree (no worktrees nested under it, checked with `git worktree list`): 18 files, 210 tests, 7.9s wall.
### Plan
1. **Red commit first.** `test/build/entrypoints.test.ts`, asserting the contract that is broken today, without needing a build:
- every `include` pattern in `tsconfig.json` roots under `compilerOptions.rootDir` — this is exactly the TS6059 precondition, and it fails at `348f23b`;
- `main`, `types` and `bin.quak` in `package.json` equal the paths `tsc` will emit for `src/index.ts` and `bin/quak.ts` given `outDir`/`rootDir`;
- the `quak` script invokes the same path as `bin.quak`;
- `bin/quak.ts` still starts with the `#!/usr/bin/env node` shebang.
2. **Take the recommended approach:** `"rootDir": "."`. Emitted layout becomes `dist/src/…` + `dist/bin/…`; `package.json` gets `main` → `./dist/src/index.js`, `types` → `./dist/src/index.d.ts`, `bin.quak` → `./dist/bin/quak.js`. This also keeps #5 possible: with `rootDir` at the repo root, `package.json` sits inside the root dir, so a relative import of it resolves under both vitest and `dist/`. I will only deviate to the shim layout if I hit a concrete obstacle, and will say what it was.
3. **`script/build`** (POSIX sh, Makefile `build` becomes a thin shim per the Scripts to Rule Them All section of `REPO_POLICIES.md`): run `tsc`, then verify on disk that each declared entrypoint exists and that the emitted CLI kept its shebang, then `chmod +x` it. Putting the artifact check in the build rather than in `make check` keeps `make check` composition untouched (test + lint + fmt-check) and keeps it independent of a prior build, while still failing loudly in CI. `package.json`'s `build` script points at `script/build` so the README's `yarn build` gets the same guarantees.
4. **`quak` script** in `package.json` so the README Getting Started commands (`yarn quak login`, ...) work after `yarn build`. README stays as-is if the invocation matches; otherwise I update the README.
5. **Dockerfile:** add `RUN make build` after the existing `RUN make check` — additive only, no change to what `make check` runs, minimal so it does not collide with #4. I will not run `docker builder prune` or `docker system prune`.
6. `make clean` already does `rm -rf dist`, which still covers the new layout; will confirm rather than assume.
7. `make fmt`, then `make check` and `make build` both green. `TODO.md` and any README change in the same commit as the implementation; commit title ends with ` (closes #3)`.
### Verification I will report
The actual `ls`-observed emitted paths for `main`, `types`, `bin.quak`, the presence of `.d.ts`/`.js.map` for the library entrypoint, the observed shebang line and mode bits of the emitted CLI, and the `make test` count/timing. Nothing goes in the PR body that I did not run in this session.
Out of scope, untouched: `engines`, `exports`, `prepublishOnly`, and anything belonging to #4, #5, #6, #13, #24, #25.
Implemented in PR #26: #26 (branch fix-ts-build-rootdir, off main at 348f23b).
Took the recommended approach — rootDir: "." — with no obstacle found, so main and types moved to ./dist/src/index.js and ./dist/src/index.d.ts and bin.quak stayed at ./dist/bin/quak.js. All three exist on disk after make build, and dist/bin/quak.js is mode -rwxr-xr-x with #!/usr/bin/env node on line 1; ./dist/bin/quak.js --help runs. make check is 19 files / 216 tests / 8.79s and make build exits 0; docker build --no-cache . ran both steps green.
Two things worth flagging against the definition of done:
Clearing TS6059 let the compiler type-check for the first time and it found two genuine errors in src/crypto/stream.ts that no build had ever reached. Both are fixed in the PR; make build could not go green without them.
Point 4 is only partly verified. The quak script exists and the built CLI runs, but the task I am working under forbids invoking yarn scripts, so I did not run yarn quak login itself. The PR body says so explicitly.
Follow-up found while working, filed separately rather than fixed here: @types/libsodium-wrappers-sumo is a deprecated stub package that ships no type definitions.
Implemented in PR #26: https://git.eeqj.de/sneak/quak/pulls/26 (branch `fix-ts-build-rootdir`, off `main` at `348f23b`).
Took the recommended approach — `rootDir: "."` — with no obstacle found, so `main` and `types` moved to `./dist/src/index.js` and `./dist/src/index.d.ts` and `bin.quak` stayed at `./dist/bin/quak.js`. All three exist on disk after `make build`, and `dist/bin/quak.js` is mode `-rwxr-xr-x` with `#!/usr/bin/env node` on line 1; `./dist/bin/quak.js --help` runs. `make check` is 19 files / 216 tests / 8.79s and `make build` exits 0; `docker build --no-cache .` ran both steps green.
Two things worth flagging against the definition of done:
- Clearing TS6059 let the compiler type-check for the first time and it found two genuine errors in `src/crypto/stream.ts` that no build had ever reached. Both are fixed in the PR; `make build` could not go green without them.
- Point 4 is only partly verified. The `quak` script exists and the built CLI runs, but the task I am working under forbids invoking yarn scripts, so I did not run `yarn quak login` itself. The PR body says so explicitly.
Follow-up found while working, filed separately rather than fixed here: `@types/libsodium-wrappers-sumo` is a deprecated stub package that ships no type definitions.
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.
Problem
make buildis broken onmainright now:tsconfig.json:8sets"rootDir": "./src"whiletsconfig.json:20sets"include": ["src/**/*", "bin/**/*"]. The two contradict each other.Nothing catches this:
make checkruns test, lint and fmt-check only (script/check), andthe Dockerfile runs
make checkbut nevermake build. So a repo whosepackage.jsondeclares
"main": "./dist/index.js"and"bin": {"quak": "./dist/bin/quak.js"}cannotproduce either artifact, and CI is blind to it.
The README's Getting Started block also tells users to run
yarn quak login,yarn quak collections, etc. There is noquakscript inpackage.json, so every one of thosecommands fails.
Definition of done
make buildsucceeds from a clean checkout and emits JavaScript plus declaration filesunder
dist/.package.jsonmain,typesandbinpoint at paths that the build actually produces,verified by inspecting
dist/after a build.#!/usr/bin/env nodeshebang frombin/quak.ts:1and is executable.
yarn quak <command>works afteryarn build, matching what the README's Getting Startedsection already promises — add the missing
quakscript topackage.json.make buildin addition tomake check, so this class of error cannever reach
mainagain. (Do not change whatmake checkitself runs — the repo policyfixes its composition as test + lint + fmt-check.)
make cleanstill removes everything the build produces.make checkgreen.TODO.mdupdated in the same commit.Recommended approach
Set
"rootDir": "."and updatepackage.jsonmain/types/binto the resultingdist/src/…anddist/bin/…paths. This is the smallest change and keeps the source layoutthe README documents.
The alternative — moving the CLI body into
src/cli.tsand leaving a thin shim inbin/—keeps
dist/index.jsas the package main but churns more files and contradicts the layoutdiagram in the README's Design section. Pick the first unless you find a concrete reason not
to, and record the reasoning in the PR body.
Out of scope
engines,exports, andprepublishOnly— tracked separately.Implementation requirements
Written against
mainat348f23b, after #1 and #2 landed.make checkis green there (18 testfiles, 210 tests, ~10s);
make buildis not.The contradiction
tsconfig.jsonsets"rootDir": "./src"and"include": ["src/**/*", "bin/**/*"]. Those cannotboth hold —
bin/quak.tsis outsiderootDir, hence TS6059. Reproduce it first viamake buildso you have the exact message in front of you before changing anything.
Nothing catches this today:
script/checkruns test, lint and fmt-check only, and the Dockerfileruns
make checkbut nevermake build. That is why a repo declaring"main": "./dist/index.js"and
"bin": {"quak": "./dist/bin/quak.js"}has been unable to produce either artifact.Take the recommended approach unless you find a real obstacle
Set
"rootDir": ".". Emitted layout becomesdist/src/…anddist/bin/…, so updatepackage.json:main→./dist/src/index.jstypes→./dist/src/index.d.tsbin.quak→./dist/bin/quak.jsThe alternative — moving the CLI body into
src/with a thin shim inbin/— keepsdist/index.jsas the package main but churns more files and contradicts the layout diagram inthe README's Design section. If you take it instead, justify it in the PR body with the specific
obstacle you hit.
Either way,
resolveJsonModuleis already on, and #5 (single-sourcing the version frompackage.json) will need to import it from the built output — so whatever layout you pick, makesure a relative import of
package.jsonwould resolve from bothsrc/under vitest and fromdist/after a build. You do not have to implement #5 here, but do not pick a layout that makesit impossible.
Verify the artifacts exist rather than assuming tsc emitted them
After
make build, confirm on disk:main,typesandbin.quakpoints at actually exists;#!/usr/bin/env nodeshebang frombin/quak.ts:1;.d.tsand.js.mapfiles are present for the library entrypoint.State the observed paths in the PR body. This repo has failed four reviews on claims that were
not checked; "the build succeeds" is not the same statement as "the declared artifacts exist".
The
quakscriptThe README's Getting Started block tells users to run
yarn quak login,yarn quak collectionsand so on. There is no
quakscript inpackage.json, so every one of those commands failstoday. Add it so the documented commands work after
yarn build. If the invocation you adddiffers from what the README shows, update the README to match — the two must agree at the end.
Dockerfile
Add
make buildto the Dockerfile so this class of error cannot reachmainagain. Do notchange what
make checkruns —REPO_POLICIES.mdfixes its composition as test + lint +fmt-check, and #4 is separately reworking the Dockerfile into a multi-stage build. Keep your change
minimal and additive so it does not collide with #4.
Note that #4 also documents a
script/cibuildcache defect: a baredocker build .can serveRUN make checkfrom cache and exit 0 without running anything. That is #4's to fix, not yours —but it means you must not treat a fast, green
docker buildas evidence your build step ran. Ifyou verify the Docker path at all, do it with
docker build --no-cache .scoped to this image.Never run
docker builder pruneordocker system prune— the BuildKit cache is shared acrossevery repo on this host and an agent elsewhere already destroyed ~41 GB of it doing exactly that.
make cleanIt must still remove everything the build now produces. If the output layout changes, update the
target.
Process
main. TDD applies as far as it sensibly can here: this is a build-configurationfix, so if you cannot write a meaningful failing test first, say so explicitly in the PR body
rather than staging a token one. A check that the declared
package.jsonentrypoints existafter a build is the closest thing to a real regression test and is worth adding.
maketargets /script/entrypoints. Never invoketsc,vitest,eslint,prettieroryarnscripts directly.make checkandmake buildmust both be green at the end. Report the measuredmake testtime — baseline ~10s at 210 tests, 20s budget, 30s hard cap.
.claude/worktrees/in thetree you are measuring. Per #25, vitest globs them and silently runs the suite N+1 times; a
polluted run reported 1050 tests where the real number is 210.
make fmt.TODO.mdand any README change go in the same commit as the implementation.(closes #3).Implementation plan
Reproduced first, on
348f23b, before touching anything.make bootstrapthenmake build:Baseline
make testin this tree (no worktrees nested under it, checked withgit worktree list): 18 files, 210 tests, 7.9s wall.Plan
Red commit first.
test/build/entrypoints.test.ts, asserting the contract that is broken today, without needing a build:includepattern intsconfig.jsonroots undercompilerOptions.rootDir— this is exactly the TS6059 precondition, and it fails at348f23b;main,typesandbin.quakinpackage.jsonequal the pathstscwill emit forsrc/index.tsandbin/quak.tsgivenoutDir/rootDir;quakscript invokes the same path asbin.quak;bin/quak.tsstill starts with the#!/usr/bin/env nodeshebang.Take the recommended approach:
"rootDir": ".". Emitted layout becomesdist/src/…+dist/bin/…;package.jsongetsmain→./dist/src/index.js,types→./dist/src/index.d.ts,bin.quak→./dist/bin/quak.js. This also keeps #5 possible: withrootDirat the repo root,package.jsonsits inside the root dir, so a relative import of it resolves under both vitest anddist/. I will only deviate to the shim layout if I hit a concrete obstacle, and will say what it was.script/build(POSIX sh, Makefilebuildbecomes a thin shim per the Scripts to Rule Them All section ofREPO_POLICIES.md): runtsc, then verify on disk that each declared entrypoint exists and that the emitted CLI kept its shebang, thenchmod +xit. Putting the artifact check in the build rather than inmake checkkeepsmake checkcomposition untouched (test + lint + fmt-check) and keeps it independent of a prior build, while still failing loudly in CI.package.json'sbuildscript points atscript/buildso the README'syarn buildgets the same guarantees.quakscript inpackage.jsonso the README Getting Started commands (yarn quak login, ...) work afteryarn build. README stays as-is if the invocation matches; otherwise I update the README.Dockerfile: add
RUN make buildafter the existingRUN make check— additive only, no change to whatmake checkruns, minimal so it does not collide with #4. I will not rundocker builder pruneordocker system prune.make cleanalready doesrm -rf dist, which still covers the new layout; will confirm rather than assume.make fmt, thenmake checkandmake buildboth green.TODO.mdand any README change in the same commit as the implementation; commit title ends with(closes #3).Verification I will report
The actual
ls-observed emitted paths formain,types,bin.quak, the presence of.d.ts/.js.mapfor the library entrypoint, the observed shebang line and mode bits of the emitted CLI, and themake testcount/timing. Nothing goes in the PR body that I did not run in this session.Out of scope, untouched:
engines,exports,prepublishOnly, and anything belonging to #4, #5, #6, #13, #24, #25.Implemented in PR #26: #26 (branch
fix-ts-build-rootdir, offmainat348f23b).Took the recommended approach —
rootDir: "."— with no obstacle found, somainandtypesmoved to./dist/src/index.jsand./dist/src/index.d.tsandbin.quakstayed at./dist/bin/quak.js. All three exist on disk aftermake build, anddist/bin/quak.jsis mode-rwxr-xr-xwith#!/usr/bin/env nodeon line 1;./dist/bin/quak.js --helpruns.make checkis 19 files / 216 tests / 8.79s andmake buildexits 0;docker build --no-cache .ran both steps green.Two things worth flagging against the definition of done:
src/crypto/stream.tsthat no build had ever reached. Both are fixed in the PR;make buildcould not go green without them.quakscript exists and the built CLI runs, but the task I am working under forbids invoking yarn scripts, so I did not runyarn quak loginitself. The PR body says so explicitly.Follow-up found while working, filed separately rather than fixed here:
@types/libsodium-wrappers-sumois a deprecated stub package that ships no type definitions.