Downgrade the four `minor` changesets (CLI color/version/help,
experimental parallel lint workers, Sentry crash reporting, and
warnings-shown-by-default) to `patch` so the next release is a single
patch bump.
Co-authored-by: Cursor <cursoragent@cursor.com>
Show "warning"-severity diagnostics by default again — a scan that reports only errors is too low a bar for a health check. Warnings reach every surface (CLI, PR comment, score, --fail-on); opt out with --no-warnings or "warnings": false. Per-rule / per-category severity overrides still win.
CLI output rework:
- Inline code frames are reserved for errors; warnings list their file:line sites compactly so a long tail of low-severity findings stays scannable.
- Non-verbose warnings roll up into a capped rule×count list (+N more rules → --verbose); errors get the same overflow line past the top 3.
- Audience-aware fix links in --verbose: coding agents get a cache-busting fetch directive, humans get a "Learn more" docs link under the rule name.
- Closing Docs note pointing to CI/CD setup, config-based rule suppression, and diff/PR scanning.
Internal: a single buildSortedRuleGroups primitive backs every rule-list surface (category breakdown, top errors, warnings roll-up, verbose detail, agent handoff, on-disk dump); shared warning-header and site-badge helpers remove the duplicated rendering.
* feat(cli): add Sentry crash reporting
Capture uncaught CLI errors via @sentry/node, flushed before the process
exits and enriched with a run-context snapshot (version, node/platform/
arch, invocation command/argv, cwd, CI provider, coding agent,
interactivity, JSON mode). Initialized as the first statement of the CLI
entry and scoped to the CLI only — the @react-doctor/api library never
initializes Sentry. Opt out via --no-score (also skipped under tests).
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor(cli): consolidate CI/agent detection into is-ci-environment
build-run-context re-declared CI provider and coding-agent env-var maps
that mirrored is-ci-environment. Move the label maps and the
detectCiProvider/detectCodingAgent resolvers into is-ci-environment as the
single source of truth, derive the flat agent env-var list from the brand
map, and have isCodingAgentEnvironment derive from detectCodingAgent.
Behavior is unchanged (env-detection tests still green).
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
ascend() re-descended the same definition subtrees on every recursion step,
so the seven State & Effects rules (led by no-pass-data-to-parent) blew up
superlinearly on large effect-heavy components — re-walking and re-scoping
identical bodies across recursion, across effects, and across rules.
Cache the downstream-reference lookup per Program node in a WeakMap keyed on
the per-Program analysis singleton (GC-bound with the file, no cross-file
bleed). Callers only ever read the returned array, so sharing it is safe.
On an 866-file Next.js app this cut ~9s (~24%) off a full scan — the worst
rule on a 1,159-line / 10-effect component dropped from ~9.5s to ~0.18s, and
the hot lint batch from ~13.5s to ~2.5s — with byte-identical diagnostics
(verified by a SHA-256 fingerprint over every diagnostic before/after).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tell the handed-off agent to verify each fix against the canonical recipe
and re-run the scan (don't assume), and add a section instructing it to
explain in plain language what each issue is, why it matters, and how
severe it is in human terms.
* feat: order the diagnostics dump by rule priority
Users report that `npx react-doctor` prints a large, undifferentiated dump and
they don't know what to tackle first. The score API now returns an intrinsic
priority/tier per rule; surface it so the dump leads with what's most worth
fixing instead of ordering purely by severity.
- core: `ScoreResult` carries the API's `rules: {ruleKey: {priority, tier}}`
payload (new `RulePriority`/`RuleTier` types); `parseScoreResult` captures it.
- CLI: rule-groups and categories sort by `effectivePriority` (API priority
desc). Unranked rules get a severity-based midpoint; with no score at all
(`--no-score` / API unreachable) ordering degrades to the previous
error-before-warning + count order, so there is no regression offline.
No priority table is duplicated here — the engine remains the single source of
truth and the values arrive over the score API.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(cli): improve error handling for command execution failures
* refactor(core): validate the score API response with effect/Schema
Replace the hand-rolled type guards in `parseScoreResult`/`parseRulePriorities`
with `effect/Schema` (the schema lib already used across @react-doctor/core, see
schemas.ts) — `Schema.Struct` + `Schema.Literals` + `Schema.Record` decoded via
`decodeUnknownOption`. A malformed payload decodes to null and falls back to the
severity ordering, same as before. Result types are now `readonly` to match the
decoded shape.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The unref-stdin live probe spawns a child Node that imports the real
.ts source, which only works where Node can natively strip TypeScript
types (>= 22.6, unflagged from 22.18). On the 20.19 CI lane there is no
type-strip path, so the child exited with empty stdout and the test
failed. Guard the suite with describe.skipIf and drop the dead
--experimental-strip-types fallback.
setup-node@v5 defaults `package-manager-cache: true`, which auto-detects
a `packageManager` field (e.g. pnpm) and runs the package manager to
resolve the cache path. Consumer CI that doesn't install pnpm fails with
"Unable to locate executable file: pnpm", which then cascades into the
skipped scan step and a "Missing report path" render crash. The action
runs via `npm exec` and never installs the consumer's deps, so there is
nothing to cache — turn it off.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(cli): pair verbose diagnostics with per-rule fix-recipe URLs
In --verbose output, every error/warning rule group now prints a
`Fix recipe:` line pointing at the canonical, reviewer-tested prompt
at https://www.react.doctor/prompts/rules/<plugin>/<rule>.md (also
written into the verbose diagnostics dump). This lets the /doctor
playbook fetch the recipe on demand so each fix follows the canonical
recipe instead of being improvised per diagnostic.
Co-authored-by: Cursor <cursoragent@cursor.com>
* chore: drop changeset for verbose fix-recipe URLs
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(cli): make verbose recipe line a fetch directive for agents
Replace the bare "Fix recipe:" label with an explicit
"Fetch & follow the canonical fix recipe before fixing:" directive so
the consuming agent treats the per-rule prompt URL as a step to perform
rather than optional reference docs. Share the line between the verbose
output and the diagnostics dump to keep them in sync.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(cli): explain per-rule recipe fetching in non-verbose summary
Non-verbose output only lists category counts, so the agent never sees
the per-rule recipe URLs. Add a closing hint that points at the
canonical recipe pattern (https://www.react.doctor/prompts/rules/<plugin>/<rule>.md)
and tells the agent to run --verbose for the exact per-rule URLs, so it
can fetch & follow the recipe before fixing.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(cli): separate recipe hint from per-project summary bars
Add a blank line before the multi-project per-project summary rows so the
recipe-fetch hint isn't visually glued to the project score bars.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(cli): include per-rule fix recipes in clipboard copy
The "Copy issues to clipboard" summary now prints each rule's canonical
fix-recipe URL (reusing the shared fetch directive) and adds a how-to-fix
step telling the agent to fetch & follow it before fixing, matching the
verbose terminal output.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(cli): show a real example recipe URL in non-verbose summary
The <plugin>/<rule>.md placeholder was ambiguous in non-verbose mode,
where the agent never sees rule names. Use a concrete recipe URL built
from an actual finding (an error when present) as the example, and point
to --verbose for the full per-rule list.
Co-authored-by: Cursor <cursoragent@cursor.com>
* style: format recipe-label constant onto a single line
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(cli): group clipboard issues by plugin/rule for correct recipe URLs
Bugbot: the clipboard summary grouped diagnostics by rule name only, so
two plugins sharing a rule name collapsed into one group and emitted the
first plugin's fix-recipe URL for all of them. Key the grouping by
`<plugin>/<rule>` (matching every other grouping in the codebase) so each
group's recipe URL and header are correct.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>