Every module is written test-first (RED, then GREEN, then refactor). CI enforces:
typecheck → lint → format → knip → unit tests → coverage (100%) → mutation (100%) → survivor registry
npm run ci| Command | What it does |
|---|---|
npm run typecheck |
tsc --noEmit |
npm run lint |
ESLint (bans as/any/!/@ts-ignore/.forEach) |
npm run format |
Prettier check |
npm run knip |
dead code / unused deps (zero findings) |
npm test |
Vitest |
npm run test:integration |
Real Chrome (set BROWSER_ENGINE_INTEGRATION=1) |
npm run showcase |
Long headed public-site demo (BROWSER_ENGINE_SHOWCASE=1) |
npm run coverage |
100% threshold (lines/branches/functions/statements) |
npm run mutation |
Stryker, 100% threshold + survivor registry |
npm run reports |
coverage + JUnit XML into reports/ |
- 100% coverage (lines/branches/functions/statements) via Vitest +
@vitest/coverage-v8. - 100% mutation score via Stryker. The only escape is a named entry in
mutation-survivors.json. - No dead code. knip runs with zero findings.
- TypeScript only. No
.js/.mjs/.cjs, including configs and scripts (emitted todist-scripts/viatsconfig.scripts.json). - No banned constructs.
as,any,!,@ts-ignore/@ts-nocheck/@ts-expect-error, and.forEachare lint errors. - Deterministic tests. Clocks and timers are injected. No sleeps.
The spec is mvp.md. Amendments in decisions.md win when they conflict. Agent rules are in ../AGENTS.md.
| Layer | Package | Version |
|---|---|---|
| Protocol | @modelcontextprotocol/server |
^2.0.0 (2026-07-28 line) |
| Browser | puppeteer |
^25.6.0 |
| Schemas | zod |
^4.4.3 |
| Language | typescript |
^6.0.3 |
| Tests | vitest |
^4.1.10 |
| Mutation | @stryker-mutator/core |
^9.6.1 |
| Lint | eslint |
^10.8.1 |
| Dead-code | knip |
^6.32.2 |
| Format | prettier |
^3.9.6 |