react-doctor 0.0.24 → 0.0.25

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
@@ -38,15 +38,15 @@ Use `--verbose` to see affected files and line numbers:
38
38
  npx -y react-doctor@latest . --verbose
39
39
  ```
40
40
 
41
- ## Install as a skill
41
+ ## Install for your coding agent
42
42
 
43
- Add React Doctor's rules as a [skill](https://skills.sh) for your coding agent:
43
+ Teach your coding agent all 47+ React best practice rules:
44
44
 
45
45
  ```bash
46
- npx skills add millionco/react-doctor
46
+ curl -fsSL https://react.doctor/install-skill.sh | bash
47
47
  ```
48
48
 
49
- This gives agents like Cursor, Claude Code, Copilot, and others access to all 47+ React best practice rules. The CLI will also prompt to install the skill on first run.
49
+ Supports Cursor, Claude Code, Amp Code, Codex, Gemini CLI, OpenCode, Windsurf, and Antigravity.
50
50
 
51
51
  ## Options
52
52
 
@@ -64,7 +64,6 @@ Options:
64
64
  --diff [base] scan only files changed vs base branch
65
65
  --no-ami skip Ami-related prompts
66
66
  --fix open Ami to auto-fix all issues
67
- --prompt copy latest scan output to clipboard
68
67
  -h, --help display help for command
69
68
  ```
70
69
 
package/dist/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
3
  import { execSync, spawn, spawnSync } from "node:child_process";
4
- import fs, { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
- import os, { homedir, tmpdir } from "node:os";
4
+ import fs, { existsSync, mkdirSync, writeFileSync } from "node:fs";
5
+ import os, { tmpdir } from "node:os";
6
6
  import path, { join } from "node:path";
7
7
  import { Command } from "commander";
8
8
  import { randomUUID } from "node:crypto";
@@ -23,7 +23,6 @@ const PERFECT_SCORE = 100;
23
23
  const SCORE_GOOD_THRESHOLD = 75;
24
24
  const SCORE_OK_THRESHOLD = 50;
25
25
  const SCORE_BAR_WIDTH_CHARS = 50;
26
- const SEPARATOR_LENGTH_CHARS = 40;
27
26
  const SUMMARY_BOX_HORIZONTAL_PADDING_CHARS = 1;
28
27
  const SUMMARY_BOX_OUTER_INDENT_CHARS = 2;
29
28
  const SCORE_API_URL = "https://www.react.doctor/api/score";
@@ -41,11 +40,6 @@ const ERROR_RULE_PENALTY = 1.5;
41
40
  const WARNING_RULE_PENALTY = .75;
42
41
  const ERROR_ESTIMATED_FIX_RATE = .85;
43
42
  const WARNING_ESTIMATED_FIX_RATE = .8;
44
- const buildDiagnosticPayload = (diagnostics) => diagnostics.map((diagnostic) => ({
45
- plugin: diagnostic.plugin,
46
- rule: diagnostic.rule,
47
- severity: diagnostic.severity
48
- }));
49
43
  const getScoreLabel = (score) => {
50
44
  if (score >= SCORE_GOOD_THRESHOLD) return "Great";
51
45
  if (score >= SCORE_OK_THRESHOLD) return "Needs work";
@@ -84,7 +78,7 @@ const calculateScore = async (diagnostics) => {
84
78
  const response = await fetch(SCORE_API_URL, {
85
79
  method: "POST",
86
80
  headers: { "Content-Type": "application/json" },
87
- body: JSON.stringify({ diagnostics: buildDiagnosticPayload(diagnostics) })
81
+ body: JSON.stringify({ diagnostics })
88
82
  });
89
83
  if (!response.ok) return null;
90
84
  return await response.json();
@@ -97,7 +91,7 @@ const fetchEstimatedScore = async (diagnostics) => {
97
91
  const response = await fetch(ESTIMATE_SCORE_API_URL, {
98
92
  method: "POST",
99
93
  headers: { "Content-Type": "application/json" },
100
- body: JSON.stringify({ diagnostics: buildDiagnosticPayload(diagnostics) })
94
+ body: JSON.stringify({ diagnostics })
101
95
  });
102
96
  if (!response.ok) return estimateScoreLocally(diagnostics);
103
97
  return await response.json();
@@ -468,57 +462,29 @@ const highlighter = {
468
462
  dim: pc.dim
469
463
  };
470
464
 
471
- //#endregion
472
- //#region src/utils/strip-ansi.ts
473
- const ANSI_ESCAPE_SEQUENCE = String.raw`\u001B\[[0-9;]*m`;
474
- const ANSI_ESCAPE_PATTERN = new RegExp(ANSI_ESCAPE_SEQUENCE, "g");
475
- const stripAnsi = (text) => text.replace(ANSI_ESCAPE_PATTERN, "");
476
-
477
465
  //#endregion
478
466
  //#region src/utils/logger.ts
479
- const loggerCaptureState = {
480
- isEnabled: false,
481
- lines: []
482
- };
483
- const captureLogLine = (text) => {
484
- if (!loggerCaptureState.isEnabled) return;
485
- loggerCaptureState.lines.push(stripAnsi(text));
486
- };
487
- const writeLogLine = (text) => {
488
- console.log(text);
489
- captureLogLine(text);
490
- };
491
- const startLoggerCapture = () => {
492
- loggerCaptureState.isEnabled = true;
493
- loggerCaptureState.lines = [];
494
- };
495
- const stopLoggerCapture = () => {
496
- const capturedOutput = loggerCaptureState.lines.join("\n");
497
- loggerCaptureState.isEnabled = false;
498
- loggerCaptureState.lines = [];
499
- return capturedOutput;
500
- };
501
467
  const logger = {
502
468
  error(...args) {
503
- writeLogLine(highlighter.error(args.join(" ")));
469
+ console.log(highlighter.error(args.join(" ")));
504
470
  },
505
471
  warn(...args) {
506
- writeLogLine(highlighter.warn(args.join(" ")));
472
+ console.log(highlighter.warn(args.join(" ")));
507
473
  },
508
474
  info(...args) {
509
- writeLogLine(highlighter.info(args.join(" ")));
475
+ console.log(highlighter.info(args.join(" ")));
510
476
  },
511
477
  success(...args) {
512
- writeLogLine(highlighter.success(args.join(" ")));
478
+ console.log(highlighter.success(args.join(" ")));
513
479
  },
514
480
  dim(...args) {
515
- writeLogLine(highlighter.dim(args.join(" ")));
481
+ console.log(highlighter.dim(args.join(" ")));
516
482
  },
517
483
  log(...args) {
518
- writeLogLine(args.join(" "));
484
+ console.log(args.join(" "));
519
485
  },
520
486
  break() {
521
- writeLogLine("");
487
+ console.log("");
522
488
  }
523
489
  };
524
490
 
@@ -1435,46 +1401,6 @@ const scan = async (directory, inputOptions = {}) => {
1435
1401
  };
1436
1402
  };
1437
1403
 
1438
- //#endregion
1439
- //#region src/utils/copy-to-clipboard.ts
1440
- const getClipboardCommands = () => {
1441
- if (process.platform === "darwin") return [{
1442
- command: "pbcopy",
1443
- args: []
1444
- }];
1445
- if (process.platform === "win32") return [{
1446
- command: "clip",
1447
- args: []
1448
- }];
1449
- return [
1450
- {
1451
- command: "wl-copy",
1452
- args: []
1453
- },
1454
- {
1455
- command: "xclip",
1456
- args: ["-selection", "clipboard"]
1457
- },
1458
- {
1459
- command: "xsel",
1460
- args: ["--clipboard", "--input"]
1461
- }
1462
- ];
1463
- };
1464
- const copyToClipboard = (text) => {
1465
- const clipboardCommands = getClipboardCommands();
1466
- for (const clipboardCommand of clipboardCommands) if (spawnSync(clipboardCommand.command, clipboardCommand.args, {
1467
- input: text,
1468
- stdio: [
1469
- "pipe",
1470
- "ignore",
1471
- "ignore"
1472
- ],
1473
- encoding: "utf8"
1474
- }).status === 0) return true;
1475
- return false;
1476
- };
1477
-
1478
1404
  //#endregion
1479
1405
  //#region src/utils/get-diff-files.ts
1480
1406
  const getCurrentBranch = (directory) => {
@@ -1520,12 +1446,33 @@ const getChangedFilesSinceBranch = (directory, baseBranch) => {
1520
1446
  return [];
1521
1447
  }
1522
1448
  };
1449
+ const getUncommittedChangedFiles = (directory) => {
1450
+ try {
1451
+ const output = execSync("git diff --name-only --diff-filter=ACMR --relative HEAD", {
1452
+ cwd: directory,
1453
+ stdio: "pipe"
1454
+ }).toString().trim();
1455
+ if (!output) return [];
1456
+ return output.split("\n").filter(Boolean);
1457
+ } catch {
1458
+ return [];
1459
+ }
1460
+ };
1523
1461
  const getDiffInfo = (directory, explicitBaseBranch) => {
1524
1462
  const currentBranch = getCurrentBranch(directory);
1525
1463
  if (!currentBranch) return null;
1526
1464
  const baseBranch = explicitBaseBranch ?? detectDefaultBranch(directory);
1527
1465
  if (!baseBranch) return null;
1528
- if (currentBranch === baseBranch) return null;
1466
+ if (currentBranch === baseBranch) {
1467
+ const uncommittedFiles = getUncommittedChangedFiles(directory);
1468
+ if (uncommittedFiles.length === 0) return null;
1469
+ return {
1470
+ currentBranch,
1471
+ baseBranch,
1472
+ changedFiles: uncommittedFiles,
1473
+ isCurrentChanges: true
1474
+ };
1475
+ }
1529
1476
  return {
1530
1477
  currentBranch,
1531
1478
  baseBranch,
@@ -1534,34 +1481,6 @@ const getDiffInfo = (directory, explicitBaseBranch) => {
1534
1481
  };
1535
1482
  const filterSourceFiles = (filePaths) => filePaths.filter((filePath) => SOURCE_FILE_PATTERN.test(filePath));
1536
1483
 
1537
- //#endregion
1538
- //#region src/utils/global-install.ts
1539
- const isGloballyInstalled = () => {
1540
- try {
1541
- return !execSync("which react-doctor", {
1542
- stdio: "pipe",
1543
- encoding: "utf-8"
1544
- }).trim().includes("/_npx/");
1545
- } catch {
1546
- return false;
1547
- }
1548
- };
1549
- const maybeInstallGlobally = () => {
1550
- try {
1551
- if (isGloballyInstalled()) return;
1552
- const child = spawn("npm", [
1553
- "install",
1554
- "-g",
1555
- "react-doctor@latest"
1556
- ], {
1557
- detached: true,
1558
- stdio: "ignore"
1559
- });
1560
- child.on("error", () => {});
1561
- child.unref();
1562
- } catch {}
1563
- };
1564
-
1565
1484
  //#endregion
1566
1485
  //#region src/utils/handle-error.ts
1567
1486
  const DEFAULT_HANDLE_ERROR_OPTIONS = { shouldExit: true };
@@ -1710,62 +1629,9 @@ const promptProjectSelection = async (workspacePackages, rootDirectory) => {
1710
1629
  return selectedDirectories;
1711
1630
  };
1712
1631
 
1713
- //#endregion
1714
- //#region src/utils/skill-prompt.ts
1715
- const CONFIG_DIRECTORY = join(homedir(), ".react-doctor");
1716
- const CONFIG_FILE = join(CONFIG_DIRECTORY, "config.json");
1717
- const SKILL_REPO = "millionco/react-doctor";
1718
- const readConfig = () => {
1719
- try {
1720
- if (!existsSync(CONFIG_FILE)) return {};
1721
- return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
1722
- } catch {
1723
- return {};
1724
- }
1725
- };
1726
- const writeConfig = (config) => {
1727
- try {
1728
- if (!existsSync(CONFIG_DIRECTORY)) mkdirSync(CONFIG_DIRECTORY, { recursive: true });
1729
- writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
1730
- } catch {}
1731
- };
1732
- const installSkill = () => {
1733
- try {
1734
- execSync(`npx -y skills add ${SKILL_REPO}`, { stdio: "inherit" });
1735
- } catch {
1736
- logger.break();
1737
- logger.dim("Skill install failed. You can install manually:");
1738
- logger.dim(` npx skills add ${SKILL_REPO}`);
1739
- }
1740
- };
1741
- const maybePromptSkillInstall = async (shouldSkipPrompts) => {
1742
- const config = readConfig();
1743
- if (config.skillPromptDismissed) return;
1744
- if (shouldSkipPrompts) return;
1745
- logger.break();
1746
- logger.log(`${highlighter.info("💡")} Have your coding agent fix these issues automatically?`);
1747
- logger.dim(` Install the ${highlighter.info("react-doctor")} skill to teach Cursor, Claude Code, Copilot,`);
1748
- logger.dim(" Ami, and other AI agents how to diagnose and fix these React issues.");
1749
- logger.break();
1750
- const { shouldInstall } = await prompts({
1751
- type: "confirm",
1752
- name: "shouldInstall",
1753
- message: "Install skill? (recommended)",
1754
- initial: true
1755
- });
1756
- if (shouldInstall) {
1757
- logger.break();
1758
- installSkill();
1759
- writeConfig({
1760
- ...config,
1761
- skillPromptDismissed: true
1762
- });
1763
- }
1764
- };
1765
-
1766
1632
  //#endregion
1767
1633
  //#region src/cli.ts
1768
- const VERSION = "0.0.24";
1634
+ const VERSION = "0.0.25";
1769
1635
  const exitWithFixHint = () => {
1770
1636
  logger.break();
1771
1637
  logger.log("Cancelled.");
@@ -1779,7 +1645,7 @@ const resolveDiffMode = async (diffInfo, effectiveDiff, shouldSkipPrompts, isSco
1779
1645
  if (effectiveDiff !== void 0 && effectiveDiff !== false) {
1780
1646
  if (diffInfo) return true;
1781
1647
  if (!isScoreOnly) {
1782
- logger.warn("Not on a feature branch or could not determine base branch. Running full scan.");
1648
+ logger.warn("No feature branch or uncommitted changes detected. Running full scan.");
1783
1649
  logger.break();
1784
1650
  }
1785
1651
  return false;
@@ -1789,18 +1655,16 @@ const resolveDiffMode = async (diffInfo, effectiveDiff, shouldSkipPrompts, isSco
1789
1655
  if (changedSourceFiles.length === 0) return false;
1790
1656
  if (shouldSkipPrompts) return true;
1791
1657
  if (isScoreOnly) return false;
1792
- const { shouldScanBranchOnly } = await prompts({
1658
+ const { shouldScanChangedOnly } = await prompts({
1793
1659
  type: "confirm",
1794
- name: "shouldScanBranchOnly",
1795
- message: `On branch ${diffInfo.currentBranch} (${changedSourceFiles.length} changed files vs ${diffInfo.baseBranch}). Only scan this branch?`,
1660
+ name: "shouldScanChangedOnly",
1661
+ message: diffInfo.isCurrentChanges ? `Found ${changedSourceFiles.length} uncommitted changed files. Only scan current changes?` : `On branch ${diffInfo.currentBranch} (${changedSourceFiles.length} changed files vs ${diffInfo.baseBranch}). Only scan this branch?`,
1796
1662
  initial: true
1797
1663
  });
1798
- return Boolean(shouldScanBranchOnly);
1664
+ return Boolean(shouldScanChangedOnly);
1799
1665
  };
1800
- 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) => {
1801
- const isScoreOnly = flags.score && !flags.prompt;
1802
- const shouldCopyPromptOutput = flags.prompt;
1803
- startLoggerCapture();
1666
+ 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").action(async (directory, flags) => {
1667
+ const isScoreOnly = flags.score;
1804
1668
  try {
1805
1669
  const resolvedDirectory = path.resolve(directory);
1806
1670
  const userConfig = loadConfig(resolvedDirectory);
@@ -1812,7 +1676,7 @@ const program = new Command().name("react-doctor").description("Diagnose React c
1812
1676
  const scanOptions = {
1813
1677
  lint: isCliOverride("lint") ? flags.lint : userConfig?.lint ?? flags.lint,
1814
1678
  deadCode: isCliOverride("deadCode") ? flags.deadCode : userConfig?.deadCode ?? flags.deadCode,
1815
- verbose: flags.prompt || (isCliOverride("verbose") ? Boolean(flags.verbose) : userConfig?.verbose ?? false),
1679
+ verbose: isCliOverride("verbose") ? Boolean(flags.verbose) : userConfig?.verbose ?? false,
1816
1680
  scoreOnly: isScoreOnly,
1817
1681
  offline: flags.offline
1818
1682
  };
@@ -1833,7 +1697,8 @@ const program = new Command().name("react-doctor").description("Diagnose React c
1833
1697
  const diffInfo = getDiffInfo(resolvedDirectory, explicitBaseBranch);
1834
1698
  const isDiffMode = await resolveDiffMode(diffInfo, effectiveDiff, shouldSkipPrompts, isScoreOnly);
1835
1699
  if (isDiffMode && diffInfo && !isScoreOnly) {
1836
- logger.log(`Scanning changes: ${highlighter.info(diffInfo.currentBranch)} → ${highlighter.info(diffInfo.baseBranch)}`);
1700
+ if (diffInfo.isCurrentChanges) logger.log("Scanning uncommitted changes");
1701
+ else logger.log(`Scanning changes: ${highlighter.info(diffInfo.currentBranch)} → ${highlighter.info(diffInfo.baseBranch)}`);
1837
1702
  logger.break();
1838
1703
  }
1839
1704
  const allDiagnostics = [];
@@ -1864,18 +1729,10 @@ const program = new Command().name("react-doctor").description("Diagnose React c
1864
1729
  allDiagnostics.push(...scanResult.diagnostics);
1865
1730
  if (!isScoreOnly) logger.break();
1866
1731
  }
1867
- const capturedScanOutput = stopLoggerCapture();
1868
1732
  if (flags.fix) openAmiToFix(resolvedDirectory);
1869
- if (shouldCopyPromptOutput) copyPromptToClipboard(capturedScanOutput, !isScoreOnly);
1870
- else if (!isScoreOnly) {
1871
- await maybePromptSkillInstall(shouldSkipAmiPrompts);
1872
- if (!shouldSkipAmiPrompts && !flags.fix) await maybePromptFix(resolvedDirectory, allDiagnostics, flags.offline ? null : await fetchEstimatedScore(allDiagnostics), capturedScanOutput);
1873
- }
1733
+ if (!isScoreOnly && !shouldSkipAmiPrompts && !flags.fix) await maybePromptFix(resolvedDirectory, allDiagnostics, flags.offline ? null : await fetchEstimatedScore(allDiagnostics));
1874
1734
  } catch (error) {
1875
- handleError(error, { shouldExit: !shouldCopyPromptOutput });
1876
- } finally {
1877
- const remainingOutput = stopLoggerCapture();
1878
- if (shouldCopyPromptOutput && remainingOutput) copyPromptToClipboard(remainingOutput, !isScoreOnly);
1735
+ handleError(error);
1879
1736
  }
1880
1737
  }).addHelpText("after", `
1881
1738
  ${highlighter.dim("Learn more:")}
@@ -1890,9 +1747,6 @@ const colorizeByScore = (text, score) => {
1890
1747
  return highlighter.error(text);
1891
1748
  };
1892
1749
  const DEEPLINK_FIX_PROMPT = "Run `npx -y react-doctor@latest .` to diagnose issues, then fix all reported issues one by one. After applying fixes, run it again to verify the results improved.";
1893
- const CLIPBOARD_FIX_PROMPT = "Fix all issues reported in the react-doctor diagnostics below, one by one. After applying fixes, run `npx -y react-doctor@latest .` again to verify the results improved.";
1894
- const REACT_DOCTOR_OUTPUT_LABEL = "react-doctor output";
1895
- const SCAN_SUMMARY_SEPARATOR = "─".repeat(SEPARATOR_LENGTH_CHARS);
1896
1750
  const isAmiInstalled = () => {
1897
1751
  if (process.platform === "darwin") return existsSync("/Applications/Ami.app") || existsSync(path.join(os.homedir(), "Applications", "Ami.app"));
1898
1752
  if (process.platform === "win32") {
@@ -1961,24 +1815,7 @@ const openAmiToFix = (directory) => {
1961
1815
  logger.info(webDeeplink);
1962
1816
  }
1963
1817
  };
1964
- const buildPromptWithOutput = (reactDoctorOutput) => {
1965
- const summaryStartIndex = reactDoctorOutput.indexOf(SCAN_SUMMARY_SEPARATOR);
1966
- const normalizedReactDoctorOutput = (summaryStartIndex === -1 ? reactDoctorOutput : reactDoctorOutput.slice(0, summaryStartIndex).trimEnd()).trim();
1967
- return `${CLIPBOARD_FIX_PROMPT}\n\n${REACT_DOCTOR_OUTPUT_LABEL}:\n\`\`\`\n${normalizedReactDoctorOutput.length > 0 ? normalizedReactDoctorOutput : "No output captured."}\n\`\`\``;
1968
- };
1969
- const copyPromptToClipboard = (reactDoctorOutput, shouldLogResult) => {
1970
- const promptWithOutput = buildPromptWithOutput(reactDoctorOutput);
1971
- const didCopyPromptToClipboard = copyToClipboard(promptWithOutput);
1972
- if (!shouldLogResult) return;
1973
- if (didCopyPromptToClipboard) {
1974
- logger.success("Copied latest scan output to clipboard");
1975
- return;
1976
- }
1977
- logger.warn("Could not copy prompt to clipboard automatically. Use this prompt:");
1978
- logger.info(promptWithOutput);
1979
- };
1980
1818
  const FIX_METHOD_AMI = "ami";
1981
- const FIX_METHOD_CLIPBOARD = "clipboard";
1982
1819
  const FIX_COMMAND_HINT = "npx react-doctor@latest --fix";
1983
1820
  const buildAmiBanner = (issueCount, currentScore, estimatedScore) => {
1984
1821
  const currentScoreDisplay = colorizeByScore(String(currentScore), currentScore);
@@ -1995,13 +1832,6 @@ const buildAmiBanner = (issueCount, currentScore, estimatedScore) => {
1995
1832
  createFramedLine(`Free to use. ${AMI_WEBSITE_URL}`, `Free to use. ${highlighter.info(AMI_WEBSITE_URL)}`)
1996
1833
  ]);
1997
1834
  };
1998
- const buildClipboardWarningBanner = () => renderFramedBoxString([
1999
- createFramedLine("⚠ Other agents may not fix these issues well.", `${highlighter.warn("⚠")} Other agents may not fix these issues well.`),
2000
- createFramedLine(""),
2001
- createFramedLine("react-doctor diagnostics require React-specific context"),
2002
- createFramedLine("that general-purpose agents often miss, leading to"),
2003
- createFramedLine("incomplete or incorrect fixes.")
2004
- ]);
2005
1835
  const buildSkipBanner = (issueCount, estimatedScore) => {
2006
1836
  const issueLabel = issueCount === 1 ? "issue" : "issues";
2007
1837
  const estimatedScoreDisplay = colorizeByScore(`~${estimatedScore}`, estimatedScore);
@@ -2014,10 +1844,9 @@ const buildSkipBanner = (issueCount, estimatedScore) => {
2014
1844
  const configureFixBanners = (issueCount, estimatedScoreResult) => {
2015
1845
  const { currentScore, estimatedScore } = estimatedScoreResult;
2016
1846
  setSelectBanner(buildAmiBanner(issueCount, currentScore, estimatedScore), 0);
2017
- setSelectBanner(buildClipboardWarningBanner(), 1);
2018
- setSelectBanner(buildSkipBanner(issueCount, estimatedScore), 2);
1847
+ setSelectBanner(buildSkipBanner(issueCount, estimatedScore), 1);
2019
1848
  };
2020
- const maybePromptFix = async (directory, diagnostics, estimatedScoreResult, capturedScanOutput) => {
1849
+ const maybePromptFix = async (directory, diagnostics, estimatedScoreResult) => {
2021
1850
  if (diagnostics.length === 0) return;
2022
1851
  logger.break();
2023
1852
  if (estimatedScoreResult) configureFixBanners(diagnostics.length, estimatedScoreResult);
@@ -2025,26 +1854,17 @@ const maybePromptFix = async (directory, diagnostics, estimatedScoreResult, capt
2025
1854
  type: "select",
2026
1855
  name: "fixMethod",
2027
1856
  message: "Fix issues?",
2028
- choices: [
2029
- {
2030
- title: "Use ami.dev (recommended)",
2031
- description: "Optimized coding agent for React Doctor",
2032
- value: FIX_METHOD_AMI
2033
- },
2034
- {
2035
- title: "Copy to clipboard",
2036
- description: "Other agents may lack context for react-doctor fixes",
2037
- value: FIX_METHOD_CLIPBOARD
2038
- },
2039
- {
2040
- title: "Skip",
2041
- value: "skip"
2042
- }
2043
- ]
1857
+ choices: [{
1858
+ title: "Use ami.dev (recommended)",
1859
+ description: "Optimized coding agent for React Doctor",
1860
+ value: FIX_METHOD_AMI
1861
+ }, {
1862
+ title: "Skip",
1863
+ value: "skip"
1864
+ }]
2044
1865
  });
2045
1866
  clearSelectBanner();
2046
1867
  if (fixMethod === FIX_METHOD_AMI) openAmiToFix(directory);
2047
- else if (fixMethod === FIX_METHOD_CLIPBOARD) copyPromptToClipboard(capturedScanOutput, true);
2048
1868
  else {
2049
1869
  logger.break();
2050
1870
  logger.dim(` Run ${highlighter.info(FIX_COMMAND_HINT)} anytime to fix issues.`);
@@ -2062,7 +1882,6 @@ const installAmiCommand = new Command("install-ami").description("Install Ami an
2062
1882
  program.addCommand(fixCommand);
2063
1883
  program.addCommand(installAmiCommand);
2064
1884
  const main$1 = async () => {
2065
- maybeInstallGlobally();
2066
1885
  await program.parseAsync();
2067
1886
  };
2068
1887
  main$1();