Diagnose a failing stage of this repo's pre-push gate, and run it correctly. Use when npm run local:gate or npm run validate fails; when lint, coverage, a smoke
复制下面这句话,粘贴给 Claude Code、Codex、Cursor 等 AI 编程工具,它会读取安装说明并在你确认后完成安装。
请阅读 https://ai.atlankj.com/install/asset/gh-pre-push-gate-0a6b7f7947f9 ,按照其中的说明把「pre-push-gate」安装到你(当前 AI 工具)中。执行前先告诉我将运行的命令和写入的位置,等我确认。
查看 AI 将读取的安装说明正在读取 GitHub 原文…
内容来自 GitHub 原始文件,由原作者维护。在 GitHub 查看
The rule (stated in AGENTS.md): run npm run format
before committing and npm run local:gate before pushing. npm run validate is the fast inner-loop check and is not a substitute — it runs no
coverage gate, no smokes, and no Storybook tests.
The reference for what each stage covers, and the CI-vs-local split, is
docs/quality-gate.md. This skill is how to
run it and what to do when it goes red.
cd <repo root>
npm run format # auto-fix: core/, scripts/, the shared surface, every client
npm run local:gate # several minutes
The stages it runs, in order, are listed in
docs/quality-gate.md — deliberately in one
place only. That list drifted apart across three copies while this PR was in
review, which is the argument for not making a fourth. npm run local:gate
prints each stage as it starts, so the running command is the other reliable
answer.
It runs every check GitHub CI runs (which additionally runs npm install,
and runs coverage as a parallel job), plus two local-only steps. So the
direction that matters holds: passing local:gate locally means every check
CI applies has already passed on your machine — the strongest predictor of a
green CI there is here, though not a proof (a different OS, and the bare test
pass noted below). The reverse does not hold at all.
One difference in invocations, not checks: CI runs each client's unit suite
twice — bare inside validate, instrumented inside coverage — on two
parallel runners, while the gate runs it once, instrumented (#2341). The
gate's first stage is local:validate, which is validate minus each client's
test leg; npm run validate itself is unchanged. The reasoning is in
AGENTS.md.
⚠️ There is no npm run ci. The gate was renamed to local:gate (#2146)
precisely because npm ci is a built-in that clean-installs from the lockfile
and does not run this script. npm run ci now fails with npm's missing-script
error.
Prettier failures are [warn] lines that match no obvious failure pattern, so a
grep-based check reports success on a red run. Capture the status:
npm run local:gate; echo "EXIT=$?"
⚠️ If you run it as a background task, the harness's "exit code 0" notification
describes the wrapper, not the gate — read the EXIT= line.
Background it and then wait for that notification — do not spend turns
watching it. The gate takes several minutes, and re-running tail or an
echo ok once per turn until it lands tells you nothing the completion
notification would not have; see Waiting on long-running
work. Waiting out one run this
way cost ~80 consecutive no-op turns on #2250.
verify:format-coverage / format:checkSomething isn't formatted, or a tracked source file is covered by no
format:check glob. Run the root npm run format (it covers core/,
scripts/, the shared surface, and every client) — not a single client's.
verify:typecheck-coverageA tracked .ts/.tsx/.mts/.cts lands in no tsconfig project. Usually a new
top-level file in a client whose build config roots at ./src; add it to that
client's tsconfig.test.json (or the src config's include).
verify:skills / verify:skills:cliA .claude/skills manifest does not parse, declares no invocation mode, or a
model-invoked skill is missing its eval cases. verify:skills:cli is the
authoritative validator and fetches a pinned CLI over the network if you have
none installed — so it is also the one stage that will fail offline.
verify:dep-lockstepA dependency reaching one tsc program from two installs resolves to two
versions. Align the versions — bump it in every install that declares it.
Do not raise the heap with --max-old-space-size; that hides the class rather
than fixing it.
verify:test-timeoutsA Vitest project resolves to a wall-clock budget nobody stated, or stopped
loading vitest.setup.shared.mts. (A retry itself fails at runtime, from
that setup file, with a message naming the test — not here.) The shared values live in vitest.shared.mts (TIMEOUTS /
INTEGRATION_TIMEOUTS) and every project spreads one of them — so raise a
budget there, not with a per-suite }, 30_000) argument, which only moves the
one site and leaves every future file on the default. A per-suite raise is
right only where the work is genuinely different (real cross-process lock
contention, a full OAuth round trip); say so at the site. retry stays unset:
it turns a load-induced red into a silent green on the only pre-push gate here.
A failing test is a different problem from a budget — read the failure before reaching for a number. An assertion that races is #1596's class and is fixed with fake timers or an awaited condition, not with headroom.
lintThere is no warning tier — every lint script runs --max-warnings 0, so a
warning fails exactly as an error does. Fix the finding; don't widen a
globalIgnores or drop the rule. If a rule genuinely must be waived on a line,
use its inline disable comment with a one-line justification.
typecheck passes locally but CI's tsc -b fails⚠️ The incremental cache hides type errors. Re-run with tsc -b --force, or
in a fresh worktree.
coverageThe per-file gate is ≥90 on all four dimensions (lines, statements,
functions, branches). A genuinely unreachable branch is annotated at the source
with a justified /* v8 ignore … -- <reason> */, never waved through by
lowering the gate. See /testing for the acceptable reasons.
Also check the file is inside a gated directory — the web coverage include is
a whitelist, so a module placed outside it falls out of the gate silently.
smoke:web*⚠️ An orphaned prod web server from a previous run fakes a rejection. It
answers the readiness probe with its token, and the deep link comes back
data-deeplink="rejected" with no error. Assert the port is free before
blaming the change.
local:storybook⚠️ In a worktree with a symlinked node_modules every story file fails on
Vite's fs.allow. Do a real npm install in the worktree.
⚠️ Two npm run local:gate runs on one machine starve each other — under four
worktrees ~326 tests timed out at 5s (#2323), and even two collide
deterministically on the web smokes' fixed ports. Since #2339 the gate takes a
machine-wide lease, so a second run queues rather than overlapping; if
everything is still timing out at once, look for what is not the gate: a
bypassed lease (INSPECTOR_SKIP_GATE_LEASE set in that shell), a bare
npm run coverage or test:storybook in another session, or Spotlight
indexing a fresh node_modules (a mdworker storm after npm install in a
new worktree pushed the load average to 20 for ten minutes). Do not write a
"wait until the machine is clear" loop — two of them deadlock on each other,
and a pgrep -f "npm run local:gate" loop matches itself and never exits.
A gate that starts with
gate-lease: pid 12345 in /Users/you/Projects/mcp-inspector-wt-1, running for 2m10s holds the gate lease; waiting …
is queued behind another worktree's gate, and will start the moment it
releases (it re-checks every 2s and prints still waiting once a minute). The
holder's pid and worktree are in the line, so you can decide whether to wait
or to stop that gate. A holder that was killed — a closed terminal, an
OOM'd session — stops refreshing its lock and is taken over after 30s; nothing
needs cleaning up by hand. The one exception is a dead holder's lock directory
that cannot be removed (a stray file inside it, or permissions): the takeover
fails, the waiter keeps waiting, and the wait runs to its 45-minute cap naming
the path — remove that directory by hand. The cap is a total wait budget, counted
from the waiter's first attempt and not reset as the queue ahead of it drains,
so a queue of healthy gates deeper than it covers — about ten, at ~4.5 minutes
each — reaches it too. So the give-up happens against a live gate that has
hung, a stale lock that would not go away, or a queue that deep; never on its
own.
INSPECTOR_SKIP_GATE_LEASE=1 npm run local:gate runs without the lease. It is
for a measurement that needs contention; it does not get a result sooner,
because the queued run finishes before an overlapped one would.
Two stages have no GitHub CI counterpart, each deliberately:
smoke:web:firefox — the three browser-driven web smokes again under
Firefox. Trialled as a CI job and removed (#2086): across a dozen runs it never
disagreed with Chromium, and playwright install --with-deps carries a real
flake surface. Kept in front of a human about to push instead.smoke:tui — needs a real TTY. It is invoked in CI via npm run smoke
and self-skips there on process.env.CI, so it needs no guarding.A guard (scripts/lib/workflow-gate.mjs, run by npm run test:scripts) fails
the suite if a workflow invokes a local:* script, a non-Chromium engine pass,
or sets SMOKE_BROWSER to anything but a literal chromium. Don't work around
it — the split is the design.
npm run pack:verify builds, packs the real tarball, installs it into a clean
throwaway consumer, and drives the installed mcp-inspector bin end to end. It
needs network access, so it is a local/release check: it is not a
local:gate stage, and CI runs it only in the publish job on a published
GitHub Release — never on a push or PR. Run it when touching packaging (the
files allowlist, a bundler external list, anything read from disk at
runtime), and as its own step when cutting a release (the release skill).