feat(uncheck): add uncheck init to set up a project - #22
Conversation
`uncheck init` sets up a new or existing project, single repo or monorepo, with the package manager it uses: it asks which tools to install (oxlint, oxfmt, and sherif at a workspace root), which tools start from the middleapi presets, whether to check every commit, and which agents run uncheck after each turn, then installs and writes the scripts and hooks. `--yes` takes the default answers without a terminal. Running it again only sets up what is missing. Package manager detection now lives in one place: the `packageManager` field, else the lockfile (Yarn 2+ also from `.yarnrc.yml`), else the one that started uncheck (`npm_config_user_agent`), else npm. The `prepare` and `hooks install` commands use it too. Their hook-writing bodies are extracted so `init` reuses them unchanged.
|
your Pullfrog Router balance is empty, and this repo has no provider key to fall back on, so the agent never ran. To fix, any one of: add a payment method or top up your Router balance · add a provider API key (GitHub Actions secret or Pullfrog secret) · switch this repo to a free model. Top up Router → · Model settings → · Setup docs → · Ask in Discord → |
commit: |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Interactive reruns can overwrite existing agent-hook flags, and malformed manifests receive misleading guidance.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Adds uncheck init for guided project setup across repositories and monorepos.
Changes:
- Detects package managers, installs tools, and creates scripts/configuration.
- Configures pre-commit and agent hooks.
- Adds comprehensive initialization tests and documentation.
| File | Description |
|---|---|
packages/uncheck/src/cli.ts |
Registers init. |
packages/uncheck/src/commands/init.ts |
Implements project initialization. |
packages/uncheck/src/commands/hooks/install.ts |
Extracts reusable agent-hook helpers. |
packages/uncheck/src/commands/prepare.ts |
Extracts pre-commit hook writing. |
packages/uncheck/src/commands/uncheck.ts |
Reuses list formatting. |
packages/uncheck/src/pm.ts |
Centralizes package-manager detection. |
packages/uncheck/src/files.ts |
Adds shared file/workspace helpers. |
packages/uncheck/src/style.ts |
Adds natural-language list formatting. |
packages/uncheck/src/checks/tsc.ts |
Uses shared file lookup. |
packages/uncheck/src/checks/sherif.ts |
Uses shared workspace detection. |
packages/uncheck/README.md |
Documents initialization. |
packages/uncheck/tests/init/defaults.test.ts |
Tests default setup. |
packages/uncheck/tests/init/package-manager.test.ts |
Tests installation behavior. |
packages/uncheck/tests/init/prompt.test.ts |
Tests interactive setup. |
packages/uncheck/tests/init/scripts.test.ts |
Tests script updates. |
packages/uncheck/tests/init/utils.ts |
Adds init test utilities. |
packages/uncheck/tests/utils/project.ts |
Supports multi-prompt terminals. |
packages/uncheck/tests/hooks/install/prompt.test.ts |
Adapts hook prompt tests. |
packages/uncheck/tests/staged/interrupt.test.ts |
Adapts terminal interruption tests. |
packages/uncheck/tests/uncheck/cli.test.ts |
Verifies command completion. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if (manifest === undefined) { | ||
| return yield* userError( | ||
| `No package.json in ${cwd} to set up: create one first, for example with \`npm init\``, | ||
| ) |
There was a problem hiding this comment.
Fixed in 5c862b9: when package.json exists but does not parse to a JSON object, init now stops with "<path>/package.json is not a JSON object, fix it and run uncheck init again" instead of telling the user to create one. Covered by tests for a syntax error and for a non-object ([]).
| const dir = yield* agentHookDir(cwd) | ||
| const offeredAgents = AGENTS.filter((agent) => dir === '' || agent.id !== 'copilot') | ||
| const unhookedAgents = yield* Effect.filter(offeredAgents, (agent) => | ||
| Effect.zipWith( | ||
| fs.exists(path.join(cwd, path.dirname(agent.path))), | ||
| hasOwnHook(cwd, agent), | ||
| (used, hooked) => used && !hooked, | ||
| ), | ||
| ) | ||
| const agents: ReadonlyArray<AgentId> = yes | ||
| ? unhookedAgents.map((agent) => agent.id) | ||
| : yield* chooseAgents(offeredAgents, { preselected: unhookedAgents }) |
There was a problem hiding this comment.
Fixed in 5c862b9: agents whose config already has an uncheck hook are no longer offered, so no choice (including "Select All") can replace their flags. They are reported as ○ <agent> <config> already runs uncheck, and the question is skipped when no agent is left to offer. Covered by a test where a hooked agent with --only=oxlint stays out of the choices and keeps its flags, and one where everything is set up and nothing is asked. The README now points to uncheck hooks install for changing those flags.
…ken package.json Agents that already run uncheck are no longer offered by `init`, so picking them can no longer replace their custom flags; they are reported as kept, and the question is skipped when no agent is left to offer. A package.json that is not a JSON object is now reported as such instead of as missing.
|
your Pullfrog Router balance is empty, and this repo has no provider key to fall back on, so the agent never ran. To fix, any one of: add a payment method or top up your Router balance · add a provider API key (GitHub Actions secret or Pullfrog secret) · switch this repo to a free model. Top up Router → · Model settings → · Setup docs → · Ask in Discord → |


npx uncheck initsets up uncheck in a new or existing project, single repo or monorepo, with the package manager the project uses. It asks which tools to install, which get a preset config, whether to check every commit and which agents run uncheck after each turn, then installs and writes the scripts and hooks. TypeScript setup is left out on purpose.What it does
oxlint.config.tsandoxfmt.config.tsfrom the middleapi presets, or.mtsin CommonJS packages, where a.tsconfig fails to load.checkandfix, plusprepare(postinstallwith Yarn 2+). Existing scripts keep their names, values and order.prepareandhooks install.--yestakes the default answers, for CI, agents and runs without a terminal.preparescript that already runsuncheck preparekeeps its hook and flags, and so do agents that already run uncheck.Package manager detection
Detection is in one place now, shared by
init,prepareandhooks install. It reads thepackageManagerfield, then the lockfile, then the tool that started uncheck (npx,pnpm dlx,yarn dlx,bunx), and falls back to npm. Yarn 2+ is also recognised from.yarnrc.yml. So a Yarn 4 project without apackageManagerfield getspostinstalland the workspace-root binary in its hooks. A project with no lockfile, set up viapnpm dlx, getspnpm exec.Testing
tests/inituse fake package managers. Three of them drive the prompts in a pseudo-terminal.src.