feat(agent): lint and format staged changes on commit - #843
Merged
Conversation
This repo had no pre-commit hook at all, so nothing checked a change until the push gate — by which point the history was already written and a lint error had to be fixed in a follow-up commit. Adds lint-staged with a hook that runs `oxlint --fix` then `dprint fmt` on staged files. oxlint here is the fast non-type-aware pass, which is what fits in the time a commit should take; the full `--type-aware` lint and the format check still run in the ship gate and CI, so this narrows the loop rather than replacing them. `--no-error-on-unmatched-pattern` is required rather than cosmetic: `.oxlintrc.json` ignores whole categories of file — `.js`, `.jsx`, `.d.ts` and `repos/**` among them — and without it oxlint exits non-zero on "No files found to lint", so staging only an ignored file would block the commit for no reason. The hook calls the lint-staged binary directly rather than `pnpm lint-staged`, for the same reason the pre-push hook stopped using `pnpm exec`: a moved lockfile makes pnpm try to purge node_modules and abort for want of a TTY. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@effect-app/cli
effect-app
@effect-app/eslint-codegen-model
@effect-app/eslint-shared-config
@effect-app/infra
@effect-app/vue
@effect-app/vue-components
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Staged changes were formatted on commit but not linted, so a lint error survived
the commit and first surfaced at the push gate or in CI — far from the change
that caused it, and after the history had already been written. Fixing it then
costs a follow-up commit on a branch that is meant to read as one increment per
change.
What
Staged code files now run
oxlint --fixbeforedprint fmt.How
oxlinthere is the fast, non-type-aware pass — what can run per file in thetime a commit should take. The full
--type-awarelint (and eslint, where therepo has it) still runs in the ship gate and CI, so this narrows the feedback
loop rather than replacing those.
Two details that are load-bearing rather than stylistic:
separate entries concurrently, and both commands rewrite the file. The globs
are disjoint for the same reason.
--no-error-on-unmatched-patternis required..oxlintrc.jsonignoreswhole categories of file, and without the flag oxlint exits non-zero on "No
files found to lint" — so staging only an ignored file would block the commit
for no reason. This was found the direct way: the first commit of this config
failed on itself.
The hook also calls the lint-staged binary directly instead of
pnpm lint-staged, for the same reason the pre-push hook stopped usingpnpm exec: amoved lockfile makes pnpm try to purge
node_modulesand abort for want of aTTY, failing the commit with an error that says nothing about linting.
Remarks
Verified both directions, since a lint step that never fails is worse than none:
a clean commit passes, and a file with
debugger/no-eval/no-unused-varsis reported and exits 1 even under
--quiet.Flow doc updated: n/a (agent tooling)
E2E coverage: n/a — commit hook, no product behaviour; exercised by every commit
Design angles: assumed goal — catch a lint error at the commit that introduced
it; pragmatic (fast oxlint pass per file, full lint stays at the gate) vs.
greenfield (one lint definition shared by hook, gate and CI, so the three cannot
drift). Pragmatic chosen — the three differ today mainly in scope and type-aware
mode, which is a larger consolidation than this change warrants.
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.