react-doctor 0.0.22 → 0.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,6 +15,15 @@ One command scans your codebase for security, performance, correctness, and arch
15
15
 
16
16
  https://github.com/user-attachments/assets/07cc88d9-9589-44c3-aa73-5d603cb1c570
17
17
 
18
+ ## How it works
19
+
20
+ React Doctor detects your framework (Next.js, Vite, Remix, etc.), React version, and compiler setup, then runs two analysis passes **in parallel**:
21
+
22
+ 1. **Lint**: Checks 60+ rules across state & effects, performance, architecture, bundle size, security, correctness, accessibility, and framework-specific categories (Next.js, React Native). Rules are toggled automatically based on your project setup.
23
+ 2. **Dead code**: Detects unused files, exports, types, and duplicates.
24
+
25
+ Diagnostics are filtered through your config, then scored by severity (errors weigh more than warnings) to produce a **0–100 health score** (75+ Great, 50–74 Needs work, <50 Critical).
26
+
18
27
  ## Install
19
28
 
20
29
  Run this at your project root:
package/dist/cli.js CHANGED
@@ -446,7 +446,7 @@ const filterIgnoredDiagnostics = (diagnostics, config) => {
446
446
  return diagnostics.filter((diagnostic) => {
447
447
  const ruleIdentifier = `${diagnostic.plugin}/${diagnostic.rule}`;
448
448
  if (ignoredRules.has(ruleIdentifier)) return false;
449
- const normalizedPath = diagnostic.filePath.replace(/\\/g, "/");
449
+ const normalizedPath = diagnostic.filePath.replace(/\\/g, "/").replace(/^\.\//, "");
450
450
  if (ignoredFilePatterns.some((pattern) => pattern.test(normalizedPath))) return false;
451
451
  return true;
452
452
  });
@@ -1759,7 +1759,7 @@ const maybePromptSkillInstall = async (shouldSkipPrompts) => {
1759
1759
 
1760
1760
  //#endregion
1761
1761
  //#region src/cli.ts
1762
- const VERSION = "0.0.22";
1762
+ const VERSION = "0.0.23";
1763
1763
  const exitWithFixHint = () => {
1764
1764
  logger.break();
1765
1765
  logger.log("Cancelled.");
@@ -1791,7 +1791,7 @@ const resolveDiffMode = async (diffInfo, effectiveDiff, shouldSkipPrompts, isSco
1791
1791
  });
1792
1792
  return Boolean(shouldScanBranchOnly);
1793
1793
  };
1794
- const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--no-lint", "skip linting").option("--no-dead-code", "skip dead code detection").option("--verbose", "show file details per rule").option("--score", "output only the score").option("-y, --yes", "skip prompts, scan all workspace projects").option("--project <name>", "select workspace project (comma-separated for multiple)").option("--diff [base]", "scan only files changed vs base branch").option("--offline", "skip telemetry (anonymous, not stored, only used to calculate score)").option("--fix", "open Ami to auto-fix all issues").option("--prompt", "copy latest scan output to clipboard").action(async (directory, flags) => {
1794
+ const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--no-lint", "skip linting").option("--no-dead-code", "skip dead code detection").option("--verbose", "show file details per rule").option("--score", "output only the score").option("-y, --yes", "skip prompts, scan all workspace projects").option("--project <name>", "select workspace project (comma-separated for multiple)").option("--diff [base]", "scan only files changed vs base branch").option("--offline", "skip telemetry (anonymous, not stored, only used to calculate score)").option("--no-ami", "skip Ami-related prompts").option("--fix", "open Ami to auto-fix all issues").option("--prompt", "copy latest scan output to clipboard").action(async (directory, flags) => {
1795
1795
  const isScoreOnly = flags.score && !flags.prompt;
1796
1796
  const shouldCopyPromptOutput = flags.prompt;
1797
1797
  startLoggerCapture();
@@ -1820,6 +1820,7 @@ const program = new Command().name("react-doctor").description("Diagnose React c
1820
1820
  process.env.AMI
1821
1821
  ].some(Boolean);
1822
1822
  const shouldSkipPrompts = flags.yes || isAutomatedEnvironment || !process.stdin.isTTY;
1823
+ const shouldSkipAmiPrompts = shouldSkipPrompts || !flags.ami;
1823
1824
  const projectDirectories = await selectProjects(resolvedDirectory, flags.project, shouldSkipPrompts);
1824
1825
  const effectiveDiff = isCliOverride("diff") ? flags.diff : userConfig?.diff;
1825
1826
  const explicitBaseBranch = typeof effectiveDiff === "string" ? effectiveDiff : void 0;
@@ -1861,8 +1862,8 @@ const program = new Command().name("react-doctor").description("Diagnose React c
1861
1862
  if (flags.fix) openAmiToFix(resolvedDirectory);
1862
1863
  if (shouldCopyPromptOutput) copyPromptToClipboard(capturedScanOutput, !isScoreOnly);
1863
1864
  else if (!isScoreOnly) {
1864
- await maybePromptSkillInstall(shouldSkipPrompts);
1865
- if (!shouldSkipPrompts && !flags.fix) await maybePromptFix(resolvedDirectory, allDiagnostics, flags.offline ? null : await fetchEstimatedScore(allDiagnostics), capturedScanOutput);
1865
+ await maybePromptSkillInstall(shouldSkipAmiPrompts);
1866
+ if (!shouldSkipAmiPrompts && !flags.fix) await maybePromptFix(resolvedDirectory, allDiagnostics, flags.offline ? null : await fetchEstimatedScore(allDiagnostics), capturedScanOutput);
1866
1867
  }
1867
1868
  } catch (error) {
1868
1869
  handleError(error, { shouldExit: !shouldCopyPromptOutput });