Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ permissions:
contents: read

jobs:
lint_and_typecheck:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
Expand All @@ -19,15 +19,13 @@ jobs:

- run: pnpm i

- run: pnpm run lint

- run: pnpm run type:check
- run: pnpm run check

test_node_matrix:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [26, 24, 22, 20]
node-version: [26, 24, 22]
fail-fast: false
steps:
- uses: actions/checkout@v7
Expand Down Expand Up @@ -59,6 +57,4 @@ jobs:

- run: pnpm i

- run: pnpm --filter='./packages/*' run -r build

- run: pnpm exec pkg-pr-new publish './packages/*' --pnpm --compact --template './playgrounds/*'
10 changes: 5 additions & 5 deletions .github/workflows/codspeed.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
name: CodSpeed

on:
push:
branches: [main]
pull_request:
branches: [main]
# push:
# branches: [main]
# pull_request:
# branches: [main]
# `workflow_dispatch` allows CodSpeed to trigger backtest
# performance analysis in order to generate initial data.
workflow_dispatch:
# workflow_dispatch:

permissions:
contents: read
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/pullfrog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ jobs:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GOOGLE_GENERATIVE_AI_API_KEY:
${{ secrets.GOOGLE_GENERATIVE_AI_API_KEY }}
GOOGLE_GENERATIVE_AI_API_KEY: ${{ secrets.GOOGLE_GENERATIVE_AI_API_KEY }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,4 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- run: pnpm --filter='./packages/*' run -r build

- run: pnpm --filter='./packages/*' publish -r --provenance --access=public --tag=${{ github.event.inputs.tag || steps.version.outputs.preid || 'latest' }} ${{ github.event.inputs.skip_git_check == 'true' && '--no-git-checks' || '' }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
!.vscode/
!.github/
!.zed/
!.oxfmtrc.json
!.oxlintrc.json

# Common generated folders
logs/
Expand Down
7 changes: 7 additions & 0 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"semi": false,
"singleQuote": true,
"arrowParens": "avoid",
"printWidth": 120
}
12 changes: 12 additions & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["typescript", "unicorn", "oxc", "import"],
"categories": {
"correctness": "error",
"suspicious": "warn"
},
"rules": {
// `Array#toSorted` is ES2023, the repo targets ES2022.
"unicorn/no-array-sort": "off"
}
}
56 changes: 7 additions & 49 deletions .zed/settings.json
Original file line number Diff line number Diff line change
@@ -1,55 +1,13 @@
{
"format_on_save": "on",
// Use ESLint's --fix:
"code_actions_on_format": {
"source.fixAll.eslint": true
},
"formatter": [],
// Enable eslint for all supported languages
// Defaults only include https://github.com/search?q=repo%3Azed-industries%2Fzed%20eslint_languages&type=code
"languages": {
"HTML": {
"language_servers": ["...", "eslint"]
},
"Markdown": {
"language_servers": ["...", "eslint"]
},
"Markdown-Inline": {
"language_servers": ["...", "eslint"]
},
"JSON": {
"language_servers": ["...", "eslint"]
},
"JSONC": {
"language_servers": ["...", "eslint"]
},
"YAML": {
"language_servers": ["...", "eslint"]
},
"CSS": {
"language_servers": ["...", "eslint"]
"formatter": {
"external": {
"command": "./node_modules/.bin/oxfmt",
"arguments": ["--stdin-filepath", "{buffer_path}"]
}
// Add other languages as needed
},
"lsp": {
"eslint": {
"settings": {
"workingDirectories": ["./"],

// Silent the stylistic rules in your IDE, but still auto fix them
"rulesCustomizations": [
{ "rule": "style/*", "severity": "off", "fixable": true },
{ "rule": "format/*", "severity": "off", "fixable": true },
{ "rule": "*-indent", "severity": "off", "fixable": true },
{ "rule": "*-spacing", "severity": "off", "fixable": true },
{ "rule": "*-spaces", "severity": "off", "fixable": true },
{ "rule": "*-order", "severity": "off", "fixable": true },
{ "rule": "*-dangle", "severity": "off", "fixable": true },
{ "rule": "*-newline", "severity": "off", "fixable": true },
{ "rule": "*quotes", "severity": "off", "fixable": true },
{ "rule": "*semi", "severity": "off", "fixable": true }
]
}
}
// Apply oxlint's auto fixes on save:
"code_actions_on_format": {
"source.fixAll.oxc": true
}
}
22 changes: 0 additions & 22 deletions eslint.config.js

This file was deleted.

37 changes: 20 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,48 +1,51 @@
{
"name": "@uncheck/repo",
"type": "module",
"version": "0.0.1",
"private": true,
"license": "MIT",
"devEngines": {
"packageManager": {
"name": "pnpm",
"version": "12.5.1",
"onFail": "download"
}
},
"type": "module",
"scripts": {
"prepare": "simple-git-hooks",
"type:check": "pnpm -r run type:check && tsc",
"check": "pnpm exec --filter=./packages/uncheck unbuild --stub && uncheck",
"fix": "pnpm run check --fix",
"test": "pnpm run -r test && vitest run",
"test:coverage": "pnpm run -r test && vitest run --coverage",
"bench": "vitest bench --run",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"repo:fix": "sherif --fix",
"sponsors:sync": "node scripts/sync-sponsors.ts && eslint --fix **/README.md"
"sponsors:sync": "node scripts/sync-sponsors.ts && pnpm check:fix '**/README.md'"
},
"devDependencies": {
"@antfu/eslint-config": "^9.5.1",
"@codspeed/vitest-plugin": "^5.7.1",
"@types/node": "^26.6.2",
"@typescript/typescript6": "^6.0.2",
"@vitest/coverage-v8": "^5.0.1",
"bumpp": "^12.3.0",
"changelogithub": "^15.0.5",
"eslint": "^10.11.0",
"eslint-plugin-format": "^2.0.1",
"lint-staged": "^17.5.1",
"oxfmt": "^0.68.0",
"oxlint": "^1.83.0",
"pkg-pr-new": "^0.0.88",
"sherif": "^1.13.0",
"simple-git-hooks": "^2.14.0",
"typescript": "^6.0.3",
"typescript": "^7.0.2",
"unbuild": "^3.6.1",
"uncheck": "workspace:*",
"vitest": "^5.0.1"
},
"simple-git-hooks": {
"pre-commit": "pnpm lint-staged"
},
"lint-staged": {
"*": "eslint --no-warn-ignored --fix"
"*": "uncheck --fix"
},
"devEngines": {
"packageManager": {
"name": "pnpm",
"version": "12.5.1",
"onFail": "download"
}
},
"engines": {
"node": ">=22.20 <23 || >=24.8"
}
}
54 changes: 53 additions & 1 deletion packages/uncheck/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<img alt="codecov" src="https://codecov.io/gh/middleapi/uncheck/branch/main/graph/badge.svg">
</a>
<a href="https://www.npmjs.com/package/uncheck">
<img alt="weekly downloads" src="https://img.shields.io/npm/dw/%40standard-server%2Fshared?logo=npm" />
<img alt="weekly downloads" src="https://img.shields.io/npm/dw/uncheck?logo=npm" />
</a>
<a href="https://app.codspeed.io/middleapi/uncheck?utm_source=badge">
<img src="https://img.shields.io/endpoint?url=https://codspeed.io/badge.json" alt="CodSpeed" />
Expand All @@ -23,6 +23,58 @@

`uncheck` is a single command that lints, formats, and type checks your project. It detects which tools the project already has — [`oxlint` and `oxfmt`](https://oxc.rs) for linting and formatting, `tsc` for types — and runs them together, so humans and coding agents have one command to remember instead of three.

## Usage

```sh
npm i -D uncheck # Node 22.20+ or 24.8+, for stable path.matchesGlob

npx uncheck # oxlint, oxfmt --check and tsc for everything under the current directory
npx uncheck --fix # oxlint --fix, then rewrite formatting with oxfmt
npx uncheck src/app # check some files: paths, directories, globs and !exclusions
npx uncheck --skip=tsc # skip a check that would otherwise run
npx uncheck --require=oxfmt # require a check: fail when it cannot run instead of skipping it
npx uncheck --cwd packages/app # run in another directory, paths are relative to it
```

Checks run in order and every check runs even if an earlier one fails, so one run reports everything. The exit code is non-zero when any check fails.

| Check | Runs when | Command |
| -------- | ------------------------------------- | -------------------------------------------------------------- |
| `oxlint` | `oxlint` is installed | `oxlint [--fix] [files...]` |
| `oxfmt` | `oxfmt` is installed | `oxfmt --check [files...]`, or `oxfmt [files...]` with `--fix` |
| `tsc` | at least one `tsconfig.json` is found | `tsc -b` for projects using references, `tsc -p` for the rest |

Paths given on the command line are resolved by `uncheck` itself into one list of files that every tool receives, so tools never disagree about what a directory or glob means: a file must exist, a directory expands to the project files below it (ignored files stay out, like `git ls-files`), globs use the usual `**`/`*` syntax and `!pattern` excludes. A path that matches nothing fails the run, unless `--no-error-on-unmatched-pattern` is passed.

Tools are resolved from `node_modules` the way Node does, so the versions your project already depends on are used. A `tsconfig.json` without `typescript` installed is reported as a failure rather than silently skipped.

### Typecheck in monorepos

Every `tsconfig.json` in the project is discovered (through `git ls-files`, so ignored folders are skipped) and its `references` are followed recursively to build the project graph:

- Projects that use `references`, or are referenced, are built with `tsc -b` on the roots of that graph. `tsc` builds the referenced projects first, in dependency order, exactly like running `tsc -b` in each package.
- Remaining standalone projects (for example a root `tsconfig.json` that only covers tests and scripts) are checked afterwards with `tsc -p`.
- Circular references are reported as an error.

When files are given, `tsc` runs only the projects it would actually check for them: a file selects the projects whose `files`, `include` and `exclude` (with `extends` applied) take it as input, so a test file excluded by its package config but included by the root config runs the root project only. Files `tsc` never checks, such as Markdown or CSS, select no project.

## Agent hooks

```sh
npx uncheck hooks install # pick agents interactively
npx uncheck hooks install claude cursor # or name them: claude, codebuddy, cursor, windsurf, copilot
```

This writes the agent's hook config (`.claude/settings.json`, `.codebuddy/settings.json`, `.cursor/hooks.json`, `.windsurf/hooks.json` or `.github/hooks/uncheck.json`), merging into an existing file so other hooks are kept. Whenever the agent finishes a turn, the hook runs:

```sh
uncheck hooks run --fix
```

through your package manager (`pnpm exec`, `yarn`, `bunx` or `npx`, detected from the lockfile). It runs every check on the files changed since the last commit (modified, staged and untracked, everything under the directory outside git), applies fixes, and prints the report on stderr. When problems remain, the agent is sent back to fix them before it finishes: Claude Code and CodeBuddy through exit code 2, Cursor through a follow-up message, Copilot through a `block` decision. That happens at most once per turn, so an agent that cannot fix something is never trapped in a loop. Windsurf only shows the report.

Running once per turn instead of after every edit keeps the agent fast: a typecheck costs seconds, and one run per turn covers everything the agent touched.

## Sponsors

Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going through [GitHub Sponsors](https://github.com/sponsors/dinwwwh) or [Open Collective](https://opencollective.com/middleapi). Every bit helps! 🚀
Expand Down
7 changes: 7 additions & 0 deletions packages/uncheck/build.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { defineBuildConfig } from 'unbuild'

export default defineBuildConfig({
rollup: {
inlineDependencies: true,
},
})
Loading
Loading