react-doctor 0.9.4-dev.da0647e → 0.9.5

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/dist/index.d.ts CHANGED
@@ -9834,13 +9834,13 @@ interface InspectResult {
9834
9834
  * Number of files the scan reported. Distinct from
9835
9835
  * `project.sourceFileCount` in diff / staged mode (where only changed
9836
9836
  * files are scanned). Optional so non-orchestrator constructors keep
9837
- * working; the multi-project summary falls back to
9837
+ * working; the multi-project report falls back to
9838
9838
  * `project.sourceFileCount` when absent.
9839
9839
  */
9840
9840
  scannedFileCount?: number;
9841
9841
  /**
9842
9842
  * Absolute paths of every file the scan considered. Lets the
9843
- * multi-project summary count UNIQUE files across projects instead of
9843
+ * multi-project report count UNIQUE files across projects instead of
9844
9844
  * summing per-project counts, which double-counts shared files when one
9845
9845
  * workspace package's tree is nested inside another's.
9846
9846
  */
@@ -9854,8 +9854,8 @@ interface InspectResult {
9854
9854
  /**
9855
9855
  * Wall-clock duration of the scan phase, in milliseconds. Distinct
9856
9856
  * from `elapsedMilliseconds` (which spans the full `inspect()` call
9857
- * including score fetch + rendering). Used by the multi-project
9858
- * summary to report combined scan time.
9857
+ * including score fetch + reporting). Used by the multi-project
9858
+ * report to show combined scan time.
9859
9859
  */
9860
9860
  scanElapsedMilliseconds?: number;
9861
9861
  /**
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6d2e43de-ae97-5213-b1a7-a9905ce4b1d5")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ca00904c-7531-5a61-a7c4-711708fe07eb")}catch(e){}}();
3
3
  import { i as __toESM$1, r as __require, t as __commonJSMin$1 } from "./chunk-ChKA3wi6.js";
4
4
  import { createRequire } from "node:module";
5
5
  import { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, REACT_DOCTOR_RULE_REGISTRY, REACT_DOCTOR_SCAN_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor/core";
@@ -62285,7 +62285,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
62285
62285
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
62286
62286
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
62287
62287
  const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
62288
- const CORE_PACKAGE_VERSION = "0.9.4";
62288
+ const CORE_PACKAGE_VERSION = "0.9.5";
62289
62289
  const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
62290
62290
  const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
62291
62291
  const SUPPLY_CHAIN_PLUGIN = "socket";
@@ -75914,4 +75914,4 @@ const toJsonReport = (result, options) => buildJsonReport({
75914
75914
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
75915
75915
 
75916
75916
  //# sourceMappingURL=index.js.map
75917
- //# debugId=6d2e43de-ae97-5213-b1a7-a9905ce4b1d5
75917
+ //# debugId=ca00904c-7531-5a61-a7c4-711708fe07eb
package/dist/lsp.js CHANGED
@@ -62384,7 +62384,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
62384
62384
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
62385
62385
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
62386
62386
  const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
62387
- const CORE_PACKAGE_VERSION = "0.9.4";
62387
+ const CORE_PACKAGE_VERSION = "0.9.5";
62388
62388
  const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
62389
62389
  const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
62390
62390
  const SUPPLY_CHAIN_PLUGIN = "socket";
@@ -75564,7 +75564,7 @@ const computeConfigFingerprint = (projectDirectory, version) => {
75564
75564
  /** Display name used in client-facing messages and progress titles. */
75565
75565
  const SERVER_DISPLAY_NAME = "React Doctor";
75566
75566
  /** Server version reported in `serverInfo`; injected at build, `dev` from source. */
75567
- const SERVER_VERSION = "0.9.4";
75567
+ const SERVER_VERSION = "0.9.5";
75568
75568
  /** `Diagnostic.source` shown next to every published diagnostic. */
75569
75569
  const DIAGNOSTIC_SOURCE = "react-doctor";
75570
75570
  /**
@@ -77298,7 +77298,7 @@ const METRIC = {
77298
77298
  tuiFindingNavigated: "tui.finding_navigated",
77299
77299
  tuiIssueStreamShown: "tui.issue_stream_shown",
77300
77300
  tuiProjectPathContextShown: "tui.project_path_context_shown",
77301
- tuiProjectSelectInlineShown: "tui.project_select_inline_shown",
77301
+ tuiProjectSelectShown: "tui.project_select_shown",
77302
77302
  tuiReportActionSelected: "tui.report_action_selected",
77303
77303
  tuiCancelled: "tui.cancelled",
77304
77304
  tuiScanInlineShown: "tui.scan_inline_shown",
@@ -77606,5 +77606,5 @@ const startLanguageServer = () => {
77606
77606
  };
77607
77607
  //#endregion
77608
77608
  export { startLanguageServer };
77609
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="8e8ec622-f2dc-5f52-bfe8-232b07051a7f")}catch(e){}}();
77610
- //# debugId=8e8ec622-f2dc-5f52-bfe8-232b07051a7f
77609
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="d3d7dbe1-3c66-52d5-be25-e0940ae870bd")}catch(e){}}();
77610
+ //# debugId=d3d7dbe1-3c66-52d5-be25-e0940ae870bd
@@ -1,7 +1,7 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ebca6a5d-3a52-5138-b882-e7cadfba9b23")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="26315528-5994-53c6-a628-8ea126913859")}catch(e){}}();
3
3
  import { n as __require, r as __toESM, t as __commonJSMin } from "./chunk-q7NCDQ7-.js";
4
- import { $ as canAnimateOnboarding, $t as isFullWidth$1, A as formatSkippedProjectsMessage, C as CLI_AGENT_BINARIES, Dr as getCategoryImpact, Er as getBaselineDiffPlan, Et as resolveScope, F as printDiagnosticsDump, Fr as isPathInsideDirectory, H as markOnboardingComplete, I as printFooter, Jn as TUI_REPORT_COMPACT_MAX_ROWS, Jr as yieldToEventLoop, Kt as findNearestPackageDirectory, M as deduplicateProjectScans, N as createInvocationInspect, Nr as highlighter, Nt as isReactDoctorWorkflowInstalled, O as buildHandoffPayload, Or as getChangedLineRanges, R as easeOutCubic, Rt as recordCount, S as detectLaunchableAgents, T as launchCliAgent, Un as CI_TRUST_COMPANIES, Ur as remainingDeadlineBudgetMs, Vr as mapWithConcurrency, Wn as METRIC, Wr as resolveScanTarget, Wt as toForwardSlashes, Yn as TUI_REPORT_DETAIL_WIDTH_FRACTION, _ as filterScansForSurface, _t as buildRulePriorityMap, a as shouldFailScanGate, at as computeProjectedScore, bt as formatLearnMoreLine, c as selectProjects, d as resolveProjectDiffIncludePaths, dt as buildCodeFrame, ei as runPromise, en as isWide$1, er as isCiEnvironment, et as isOnboardingForced, f as resolveProjectSourceFilePaths, ft as buildEmptyReportMessage, g as resolveCliInspectOptions, gt as hasLintHardFailure, h as resolveWorkspaceDeadCodeOwner, ht as resolveMergeBaseRef, ii as void_, it as filterDiagnosticsByCategories, j as collectProjectSourceFileCounts, jr as hasPublishedFixRecipe, k as isShareOptedOut, kn as cliLogger, kr as getDiffInfo, kt as resolveBlockingLevel, l as resolveProjectScan, lr as DIAGNOSTIC_CATEGORY_BUCKETS, m as retryMissingProjectScores, mr as Reporter, mt as buildNoScoreMessage, n as registerActiveTuiRenderer, nn as isUnicodeSupported, o as projectManifestChanged, oi as succeed, ot as formatElapsedTime, pr as Progress, pt as hasIncompleteScoreAnalysis, r as validateIncludeUntrackedScope, ri as sync, rn as chalk, rt as supportsHyperlinks, s as discoverWorkspacePackages, t as exitGracefully, tn as stripAnsi, tt as shouldRecordOnboarding, u as resolveProjectChangedLineRanges, ur as GITHUB_ACTIONS_SETUP_URL, ut as formatHyperlink, v as countUniqueScannedFiles, vt as buildSortedRuleGroups, w as copyToClipboard, wt as finalizeScope, x as openUrl, y as setUpGitHubActions, yr as buildRuleDocsUrl, yt as formatFixRecipeLine, z as doctorFace, zt as recordDistribution } from "./exit-gracefully-BN2OivAV.js";
4
+ import { $ as filterDiagnosticsByCategories, $n as GITHUB_ACTIONS_SETUP_URL, B as buildHandoffPayload, C as isGatePending, Cr as highlighter, Dt as recordDistribution, Et as recordCount, F as CLI_AGENT_BINARIES, Gr as sync, Gt as chalk, H as collectProjectSourceFileCounts, Ht as isWide$1, I as copyToClipboard, J as formatElapsedTime, Jr as succeed, Kr as void_, L as launchCliAgent, Ln as TUI_REPORT_COMPACT_MAX_ROWS, M as ONBOARDING_EVENT, Mn as METRIC, Mt as toForwardSlashes, Nr as remainingDeadlineBudgetMs, P as detectLaunchableAgents, Pr as resolveScanTarget, Pt as findNearestPackageDirectory, Q as formatDiagnosticSite, Qn as DIAGNOSTIC_CATEGORY_BUCKETS, Rn as TUI_REPORT_DETAIL_WIDTH_FRACTION, Rr as yieldToEventLoop, S as openUrl, T as recordGate, Tr as isPathInsideDirectory, U as deduplicateProjectScans, Un as isCiEnvironment, Ur as runPromise, Ut as stripAnsi, V as formatSkippedProjectsMessage, Vn as isGitHookEnvironment, Vt as isFullWidth$1, W as createInvocationInspect, Wt as isUnicodeSupported, Y as printFooter, Z as printDiagnosticsDump, _ as resolveCliInspectOptions, _n as cliLogger, _r as getCategoryImpact, _t as resolveBlockingLevel, a as shouldFailScanGate, at as buildRulePriorityMap, b as setUpGitHubActions, c as selectProjects, cr as buildRuleDocsUrl, ct as formatLearnMoreLine, d as resolveProjectChangedLineRanges, et as buildEmptyReportMessage, f as resolveProjectDiffIncludePaths, ft as finalizeScope, g as resolveWorkspaceDeadCodeOwner, gr as getBaselineDiffPlan, h as retryMissingProjectScores, it as hasLintHardFailure, jn as CI_TRUST_COMPANIES, jr as mapWithConcurrency, l as buildCodeFrame, lr as calculateScore, mt as resolveScope, n as registerActiveTuiRenderer, nr as Progress, nt as buildNoScoreMessage, o as projectManifestChanged, ot as buildSortedRuleGroups, p as resolveProjectSourceFilePaths, q as pluralize, r as validateIncludeUntrackedScope, rr as Reporter, rt as resolveMergeBaseRef, s as discoverWorkspacePackages, st as formatFixRecipeLine, t as exitGracefully, tt as hasIncompleteScoreAnalysis, u as resolveProjectScan, v as filterScansForSurface, vr as getChangedLineRanges, xr as hasPublishedFixRecipe, xt as isReactDoctorWorkflowInstalled, y as countUniqueScannedFiles, yr as getDiffInfo } from "./exit-gracefully-B18ck0kt.js";
5
5
  import { EventEmitter } from "node:events";
6
6
  import { execFileSync } from "node:child_process";
7
7
  import path from "node:path";
@@ -20946,24 +20946,24 @@ const BEL = "\x07";
20946
20946
  const ESC = "\x1B";
20947
20947
  const BACKSLASH = "\\";
20948
20948
  const CSI = "[";
20949
- const OSC = "]";
20949
+ const OSC$1 = "]";
20950
20950
  const C1_ST = "œ";
20951
20951
  const CC_BEL = BEL.charCodeAt(0);
20952
20952
  const CC_ESC = ESC.charCodeAt(0);
20953
20953
  const CC_BACKSLASH = BACKSLASH.charCodeAt(0);
20954
20954
  const CC_CSI = CSI.charCodeAt(0);
20955
- const CC_OSC = OSC.charCodeAt(0);
20955
+ const CC_OSC = OSC$1.charCodeAt(0);
20956
20956
  const CC_C1_ST = C1_ST.charCodeAt(0);
20957
20957
  "0".charCodeAt(0);
20958
20958
  "9".charCodeAt(0);
20959
20959
  ";".charCodeAt(0);
20960
20960
  "m".charCodeAt(0);
20961
20961
  const ESCAPES = new Set([CC_ESC, 155]);
20962
- const linkCodePrefix = `${ESC}${OSC}8;`;
20962
+ const linkCodePrefix = `${ESC}${OSC$1}8;`;
20963
20963
  const linkCodePrefixCharCodes = linkCodePrefix.split("").map((char) => char.charCodeAt(0));
20964
- const linkEndCode = `${ESC}${OSC}8;;${BEL}`;
20965
- const linkEndCodeST = `${ESC}${OSC}8;;${ESC}${BACKSLASH}`;
20966
- const linkEndCodeC1ST = `${ESC}${OSC}8;;${C1_ST}`;
20964
+ const linkEndCode = `${ESC}${OSC$1}8;;${BEL}`;
20965
+ const linkEndCodeST = `${ESC}${OSC$1}8;;${ESC}${BACKSLASH}`;
20966
+ const linkEndCodeC1ST = `${ESC}${OSC$1}8;;${C1_ST}`;
20967
20967
  //#endregion
20968
20968
  //#region ../../node_modules/.pnpm/@alcalzone+ansi-tokenize@0.3.0/node_modules/@alcalzone/ansi-tokenize/build/ansiCodes.js
20969
20969
  const endCodesSet = /* @__PURE__ */ new Set();
@@ -23957,8 +23957,20 @@ A React hook that returns the stdout stream where Ink renders your app.
23957
23957
  */
23958
23958
  const useStdout = () => (0, import_react.useContext)(StdoutContext);
23959
23959
  //#endregion
23960
- //#region src/cli/utils/pluralize.ts
23961
- const pluralize = (count, singularNoun) => `${count} ${singularNoun}${count === 1 ? "" : "s"}`;
23960
+ //#region src/cli/utils/get-top-error-rule-keys.ts
23961
+ const getTopErrorRuleKeys = (diagnostics, limit, rulePriority) => new Set(buildSortedRuleGroups(diagnostics.filter((diagnostic) => diagnostic.severity === "error"), rulePriority).slice(0, limit).map(([ruleKey]) => ruleKey));
23962
+ //#endregion
23963
+ //#region src/cli/utils/compute-score-projection.ts
23964
+ const computeProjectedScore = async (topErrorSource, rescoreSource, currentScore) => {
23965
+ const topErrorRuleKeys = getTopErrorRuleKeys(topErrorSource, 3, buildRulePriorityMap([currentScore]));
23966
+ if (topErrorRuleKeys.size === 0) return null;
23967
+ const potentialScore = await calculateScore(rescoreSource.filter((diagnostic) => !topErrorRuleKeys.has(`${diagnostic.plugin}/${diagnostic.rule}`)));
23968
+ if (!potentialScore || potentialScore.score <= currentScore.score) return null;
23969
+ return potentialScore.score;
23970
+ };
23971
+ //#endregion
23972
+ //#region src/cli/utils/is-share-opted-out.ts
23973
+ const isShareOptedOut = (scans, flagNoScore) => Boolean(flagNoScore) || scans.some((scan) => Boolean(scan.config?.noScore) || scan.config?.share === false);
23962
23974
  //#endregion
23963
23975
  //#region src/cli/utils/resolve-project-tui-scan-scope.ts
23964
23976
  const resolveProjectTuiScanScope = (input) => {
@@ -24050,9 +24062,10 @@ const resolveVisibleStart = ({ itemCount, offset, selectedIndex, viewportHeight
24050
24062
  //#endregion
24051
24063
  //#region src/cli/ink/hooks/use-exit-on-ctrl-c.ts
24052
24064
  const SHOW_CURSOR = "\x1B[?25h";
24053
- const useExitOnCtrlC = () => {
24065
+ const useExitOnCtrlC = (onCancel) => {
24054
24066
  useInput((input, key) => {
24055
24067
  if (key.ctrl && input === "c") {
24068
+ onCancel?.();
24056
24069
  recordCount(METRIC.tuiCancelled, 1, { resourceFooter: true });
24057
24070
  process.stdin.setRawMode?.(false);
24058
24071
  process.stdout.write(SHOW_CURSOR);
@@ -24577,6 +24590,33 @@ const ProjectSelect = ({ packages, rootDirectory, onSubmit }) => {
24577
24590
  });
24578
24591
  };
24579
24592
  //#endregion
24593
+ //#region src/cli/utils/onboarding-pacing.ts
24594
+ const FORCE_ONBOARDING_ENV_VAR = "REACT_DOCTOR_FORCE_ONBOARDING";
24595
+ const FALSY_FLAG_VALUES = new Set([
24596
+ "",
24597
+ "0",
24598
+ "false"
24599
+ ]);
24600
+ const isOnboardingForced = (environment = process.env) => {
24601
+ const value = environment[FORCE_ONBOARDING_ENV_VAR];
24602
+ return value !== void 0 && !FALSY_FLAG_VALUES.has(value.toLowerCase());
24603
+ };
24604
+ const shouldRecordOnboarding = (input) => input.paceOnboardingSections && !input.forceOnboarding && !input.verbose && !input.isNonInteractiveEnvironment;
24605
+ const canAnimateOnboarding = (stream = process.stdout) => {
24606
+ if (!(stream.isTTY === true && (stream.columns ?? 0) > 0 && process.env.TERM !== "dumb")) return false;
24607
+ if (isOnboardingForced()) return true;
24608
+ return !isGitHookEnvironment() && !isCiEnvironment();
24609
+ };
24610
+ //#endregion
24611
+ //#region src/cli/utils/onboarding-state.ts
24612
+ const ONBOARDING_GATE = {
24613
+ id: ONBOARDING_EVENT,
24614
+ scope: "global"
24615
+ };
24616
+ const markOnboardingComplete = (options = {}) => {
24617
+ if (isGatePending(ONBOARDING_GATE, {}, options)) recordGate(ONBOARDING_GATE, {}, options);
24618
+ };
24619
+ //#endregion
24580
24620
  //#region src/cli/ink/hooks/use-report-reveal.ts
24581
24621
  const useReportReveal = ({ issueCount, onRevealComplete }) => {
24582
24622
  const { stdout } = useStdout();
@@ -24652,9 +24692,6 @@ const buildDiagnosticListEntries = (rows) => {
24652
24692
  return entries;
24653
24693
  };
24654
24694
  //#endregion
24655
- //#region src/cli/utils/format-diagnostic-site.ts
24656
- const formatDiagnosticSite = (site) => site.line > 0 ? `${site.filePath}:${site.line}` : site.filePath;
24657
- //#endregion
24658
24695
  //#region src/cli/ink/lib/diagnostic-rows.ts
24659
24696
  const buildDiagnosticRows = (diagnostics, scores) => {
24660
24697
  return buildSortedRuleGroups(diagnostics, buildRulePriorityMap(scores)).map(([ruleKey, ruleDiagnostics]) => {
@@ -24774,6 +24811,50 @@ const AgentHandoff = ({ agents, onSelect, onBack, onQuit }) => {
24774
24811
  });
24775
24812
  };
24776
24813
  //#endregion
24814
+ //#region src/cli/utils/format-hyperlink.ts
24815
+ const OSC = "\x1B]";
24816
+ const ST = "\x1B\\";
24817
+ /**
24818
+ * Wraps `text` in an OSC 8 hyperlink pointing at `uri`. The visible characters
24819
+ * are exactly `text`; the link is carried in escape sequences a capable
24820
+ * terminal turns into a click target.
24821
+ */
24822
+ const formatHyperlink = (text, uri) => `${OSC}8;;${uri}${ST}${text}${OSC}8;;${ST}`;
24823
+ //#endregion
24824
+ //#region src/cli/utils/supports-hyperlinks.ts
24825
+ const HYPERLINK_CAPABLE_TERM_PROGRAMS = new Set([
24826
+ "iTerm.app",
24827
+ "WezTerm",
24828
+ "vscode",
24829
+ "Hyper",
24830
+ "ghostty",
24831
+ "Tabby",
24832
+ "rio"
24833
+ ]);
24834
+ const parseVteVersion = (raw) => {
24835
+ const parsed = Number.parseInt(raw ?? "", 10);
24836
+ return Number.isNaN(parsed) ? 0 : parsed;
24837
+ };
24838
+ /**
24839
+ * Whether `stream` is a terminal that renders OSC 8 hyperlinks. Auto-detected
24840
+ * from terminal-identity env vars; the de-facto `FORCE_HYPERLINK` env var
24841
+ * overrides detection (`FORCE_HYPERLINK=0`/`false` forces off, any other value
24842
+ * forces on), mirroring how the ecosystem's terminal libraries gate the same
24843
+ * feature. Off for non-TTYs, `TERM=dumb`, and CI (whose log viewers render the
24844
+ * raw escape rather than a link). Unknown terminals default to off.
24845
+ */
24846
+ const supportsHyperlinks = (stream = process.stdout, env = process.env) => {
24847
+ const forced = env.FORCE_HYPERLINK;
24848
+ if (forced !== void 0 && forced !== "") return forced !== "0" && forced.toLowerCase() !== "false";
24849
+ if (stream.isTTY !== true) return false;
24850
+ if (env.TERM === "dumb") return false;
24851
+ if (isCiEnvironment(env)) return false;
24852
+ if (env.WT_SESSION) return true;
24853
+ if (env.KITTY_WINDOW_ID || env.TERM === "xterm-kitty") return true;
24854
+ if (parseVteVersion(env.VTE_VERSION) >= 5e3) return true;
24855
+ return Boolean(env.TERM_PROGRAM && HYPERLINK_CAPABLE_TERM_PROGRAMS.has(env.TERM_PROGRAM));
24856
+ };
24857
+ //#endregion
24777
24858
  //#region src/cli/ink/components/tui-link.tsx
24778
24859
  const TuiLink = ({ children, url }) => {
24779
24860
  const shouldFormatHyperlink = supportsHyperlinks();
@@ -25528,6 +25609,16 @@ const ReportIssueStream = ({ rows, selectedIndex, width }) => {
25528
25609
  });
25529
25610
  };
25530
25611
  //#endregion
25612
+ //#region src/cli/utils/doctor-face.ts
25613
+ const doctorFace = (score) => {
25614
+ if (score >= 75) return ["◠ ◠", " ▽ "];
25615
+ if (score >= 50) return ["• •", " ─ "];
25616
+ return ["x x", " ▽ "];
25617
+ };
25618
+ //#endregion
25619
+ //#region src/cli/utils/ease-out-cubic.ts
25620
+ const easeOutCubic = (progress) => 1 - (1 - progress) ** 3;
25621
+ //#endregion
25531
25622
  //#region src/cli/ink/hooks/use-animated-score.ts
25532
25623
  const useAnimatedScore = ({ score, projectedScore, shouldAnimate }) => {
25533
25624
  const projectionTarget = projectedScore ?? score;
@@ -27624,7 +27715,7 @@ const useScanStore = (store) => (0, import_react.useSyncExternalStore)(store.sub
27624
27715
  const ScanApp = ({ store, displayMode = "report", launchableAgents, onHandoff, canAddToCi, onAddToCi, onQuit }) => {
27625
27716
  const snapshot = useScanStore(store);
27626
27717
  const { exit } = useApp();
27627
- useExitOnCtrlC();
27718
+ useExitOnCtrlC(onQuit);
27628
27719
  const handleQuit = () => {
27629
27720
  onQuit?.();
27630
27721
  exit();
@@ -27781,10 +27872,24 @@ const resolveSelectedDirectories = async (rootDirectory, input) => {
27781
27872
  if (!(packages.length > 1 && !input.projectFlag && !input.skipPrompts && (input.configProjects ?? []).length === 0 && process.stdin.isTTY === true)) return selectProjects(rootDirectory, input.projectFlag, input.skipPrompts ?? false, input.configProjects);
27782
27873
  return promptProjectSelection(packages, rootDirectory);
27783
27874
  };
27875
+ const registerMountedTuiRenderer = (instance) => {
27876
+ let didDisposeRenderer = false;
27877
+ const disposeRenderer = (shouldClearOutput) => {
27878
+ if (didDisposeRenderer) return;
27879
+ didDisposeRenderer = true;
27880
+ if (shouldClearOutput) instance.clear();
27881
+ instance.unmount();
27882
+ };
27883
+ const unregisterActiveTuiRenderer = registerActiveTuiRenderer({ preserveOutput: () => disposeRenderer(false) });
27884
+ return () => {
27885
+ unregisterActiveTuiRenderer();
27886
+ disposeRenderer(true);
27887
+ };
27888
+ };
27784
27889
  const promptProjectSelection = (packages, rootDirectory) => new Promise((resolve) => {
27785
27890
  let disposeRenderer = () => {};
27786
- recordCount(METRIC.tuiProjectSelectInlineShown);
27787
- const instance = render(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProjectSelect, {
27891
+ recordCount(METRIC.tuiProjectSelectShown);
27892
+ disposeRenderer = registerMountedTuiRenderer(render(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProjectSelect, {
27788
27893
  packages,
27789
27894
  rootDirectory,
27790
27895
  onSubmit: (directories) => {
@@ -27792,21 +27897,9 @@ const promptProjectSelection = (packages, rootDirectory) => new Promise((resolve
27792
27897
  resolve(directories);
27793
27898
  }
27794
27899
  }), {
27795
- alternateScreen: false,
27900
+ alternateScreen: true,
27796
27901
  exitOnCtrlC: false
27797
- });
27798
- let didClearRenderer = false;
27799
- const clearRenderer = () => {
27800
- if (didClearRenderer) return;
27801
- didClearRenderer = true;
27802
- instance.clear();
27803
- instance.unmount();
27804
- };
27805
- const unregisterActiveTuiRenderer = registerActiveTuiRenderer({ clear: clearRenderer });
27806
- disposeRenderer = () => {
27807
- unregisterActiveTuiRenderer();
27808
- clearRenderer();
27809
- };
27902
+ }));
27810
27903
  });
27811
27904
  const resolveLintFailureReason = (results) => {
27812
27905
  for (const result of results) {
@@ -27905,20 +27998,9 @@ const mountScanApp = async (rootDirectory, shouldRecommendCi, initialProgress) =
27905
27998
  alternateScreen: false,
27906
27999
  exitOnCtrlC: false
27907
28000
  });
27908
- let didClearRenderer = false;
27909
- const clearRenderer = () => {
27910
- if (didClearRenderer) return;
27911
- didClearRenderer = true;
27912
- instance.clear();
27913
- instance.unmount();
27914
- };
27915
- const unregisterActiveTuiRenderer = registerActiveTuiRenderer({ clear: clearRenderer });
27916
28001
  return {
27917
28002
  instance,
27918
- dispose: () => {
27919
- unregisterActiveTuiRenderer();
27920
- clearRenderer();
27921
- }
28003
+ dispose: registerMountedTuiRenderer(instance)
27922
28004
  };
27923
28005
  };
27924
28006
  const executePendingActions = async () => {
@@ -28225,5 +28307,5 @@ const runScanApp = async (input) => {
28225
28307
  //#endregion
28226
28308
  export { runScanApp };
28227
28309
 
28228
- //# sourceMappingURL=run-scan-app-_1xMQtKK.js.map
28229
- //# debugId=ebca6a5d-3a52-5138-b882-e7cadfba9b23
28310
+ //# sourceMappingURL=run-scan-app-CjGdpTbP.js.map
28311
+ //# debugId=26315528-5994-53c6-a628-8ea126913859
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.9.4-dev.da0647e",
3
+ "version": "0.9.5",
4
4
  "description": "Your agent writes bad React. This catches it",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -69,8 +69,8 @@
69
69
  "vscode-uri": "^3.1.0",
70
70
  "yaml": "^2.9.0",
71
71
  "yoga-layout": "~3.2.1",
72
- "deslop-js": "0.9.4",
73
- "oxlint-plugin-react-doctor": "0.9.4-dev.da0647e"
72
+ "deslop-js": "0.9.5",
73
+ "oxlint-plugin-react-doctor": "0.9.5"
74
74
  },
75
75
  "devDependencies": {
76
76
  "@types/babel__code-frame": "^7.27.0",
@@ -84,9 +84,9 @@
84
84
  "ora": "^9.4.0",
85
85
  "react": "19.2.5",
86
86
  "react-devtools-core": "^7.0.1",
87
- "@react-doctor/api": "0.9.4",
88
- "@react-doctor/core": "0.9.4",
89
- "@react-doctor/language-server": "0.9.4"
87
+ "@react-doctor/api": "0.9.5",
88
+ "@react-doctor/core": "0.9.5",
89
+ "@react-doctor/language-server": "0.9.5"
90
90
  },
91
91
  "engines": {
92
92
  "node": "^20.19.0 || >=22.13.0"