react-doctor 0.5.6-dev.5b742fa → 0.5.6-dev.7d9e676

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/cli.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]="54905d6a-f06f-5f80-9fb6-7d4ab857d553")}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]="3622d8e5-b640-5cae-addd-2b990604cce2")}catch(e){}}();
3
3
  import { createRequire } from "node:module";
4
4
  import * as NodeChildProcess from "node:child_process";
5
5
  import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
@@ -39692,15 +39692,10 @@ const buildCapabilities = (project) => {
39692
39692
  }
39693
39693
  if (project.tailwindVersion !== null) {
39694
39694
  capabilities.add("tailwind");
39695
- const tailwind = parseTailwindMajorMinor(project.tailwindVersion);
39696
- if (isTailwindAtLeast(tailwind, {
39695
+ if (isTailwindAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
39697
39696
  major: 3,
39698
39697
  minor: 4
39699
39698
  })) capabilities.add("tailwind:3.4");
39700
- if (tailwind !== null && isTailwindAtLeast(tailwind, {
39701
- major: 4,
39702
- minor: 0
39703
- })) capabilities.add("tailwind:4");
39704
39699
  }
39705
39700
  if (project.zodVersion !== null) {
39706
39701
  capabilities.add("zod");
@@ -41325,8 +41320,8 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
41325
41320
  }
41326
41321
  return enabled;
41327
41322
  };
41328
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [] }) => {
41329
- const reactHooksJsPlugin = resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
41323
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false }) => {
41324
+ const reactHooksJsPlugin = disableReactHooksJsPlugin ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
41330
41325
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
41331
41326
  const jsPlugins = [];
41332
41327
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -42023,9 +42018,9 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
42023
42018
  try {
42024
42019
  parsed = JSON.parse(sanitizedStdout);
42025
42020
  } catch {
42026
- throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 200) }) });
42021
+ throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
42027
42022
  }
42028
- if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 200) }) });
42023
+ if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
42029
42024
  const minifiedFileCache = /* @__PURE__ */ new Map();
42030
42025
  const isMinifiedDiagnosticFile = (filename) => {
42031
42026
  const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
@@ -42316,6 +42311,28 @@ const writeOxlintConfig = (configPath, configToWrite) => {
42316
42311
  NFS.closeSync(fileHandle);
42317
42312
  }
42318
42313
  };
42314
+ const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
42315
+ /**
42316
+ * Detects an oxlint config-load crash caused by the optional
42317
+ * `react-hooks-js` (eslint-plugin-react-hooks) React Compiler plugin and
42318
+ * builds the partial-failure note for it; returns `null` when the failure
42319
+ * was anything else.
42320
+ *
42321
+ * oxlint prints a framed error to stdout (not stderr) and exits non-zero
42322
+ * when a `jsPlugins` entry can't be imported; that non-JSON stdout
42323
+ * surfaces as `OxlintOutputUnparseable`. Because oxlint fails the WHOLE
42324
+ * config load on it, leaving the plugin in would drop every curated
42325
+ * react-doctor diagnostic too — so the caller retries with the plugin
42326
+ * stripped (issue #833). Both markers sit at the start of oxlint's
42327
+ * message, so they survive the `preview` slice even for deep pnpm paths.
42328
+ */
42329
+ const reactHooksJsPluginDropNote = (error) => {
42330
+ if (!(error instanceof ReactDoctorError) || error.reason._tag !== "OxlintOutputUnparseable") return null;
42331
+ const { preview } = error.reason;
42332
+ if (!preview.includes("Failed to load JS plugin") || !preview.includes("eslint-plugin-react-hooks")) return null;
42333
+ const underlyingReason = preview.match(/Error:[^\n]*/)?.[0]?.trim();
42334
+ return `${REACT_HOOKS_JS_DROP_PREFIX}${underlyingReason ? `: ${underlyingReason}` : ""}. Other rules ran normally.`;
42335
+ };
42319
42336
  /**
42320
42337
  * The oxlint runner. Composed of three pieces in `runners/oxlint/`:
42321
42338
  *
@@ -42343,15 +42360,16 @@ const runOxlint = async (options) => {
42343
42360
  const pluginPath = resolvePluginPath();
42344
42361
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
42345
42362
  const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
42346
- const buildConfig = (extendsForThisAttempt) => createOxlintConfig({
42363
+ const buildConfig = (overrides) => createOxlintConfig({
42347
42364
  pluginPath,
42348
42365
  project,
42349
42366
  customRulesOnly,
42350
- extendsPaths: extendsForThisAttempt,
42367
+ extendsPaths: overrides.extendsPaths,
42351
42368
  ignoredTags,
42352
42369
  serverAuthFunctionNames,
42353
42370
  severityControls,
42354
- userPlugins
42371
+ userPlugins,
42372
+ disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
42355
42373
  });
42356
42374
  const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
42357
42375
  const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
@@ -42387,12 +42405,22 @@ const runOxlint = async (options) => {
42387
42405
  outputMaxBytes,
42388
42406
  concurrency: options.concurrency
42389
42407
  });
42390
- writeOxlintConfig(configPath, buildConfig(extendsPaths));
42408
+ writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
42391
42409
  try {
42392
42410
  return await runBatches();
42393
42411
  } catch (error) {
42412
+ const reactHooksJsDropNote = reactHooksJsPluginDropNote(error);
42413
+ if (reactHooksJsDropNote !== null) {
42414
+ writeOxlintConfig(configPath, buildConfig({
42415
+ extendsPaths,
42416
+ disableReactHooksJsPlugin: true
42417
+ }));
42418
+ const diagnostics = await runBatches();
42419
+ onPartialFailure?.(reactHooksJsDropNote);
42420
+ return diagnostics;
42421
+ }
42394
42422
  if (extendsPaths.length === 0) throw error;
42395
- writeOxlintConfig(configPath, buildConfig([]));
42423
+ writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
42396
42424
  return await runBatches();
42397
42425
  }
42398
42426
  } finally {
@@ -43891,6 +43919,7 @@ const NON_INTERACTIVE_ENVIRONMENT_VARIABLES = [
43891
43919
  const isNonInteractiveEnvironment = () => NON_INTERACTIVE_ENVIRONMENT_VARIABLES.some((envVariable) => Boolean(process.env[envVariable])) || isCodingAgentEnvironment();
43892
43920
  //#endregion
43893
43921
  //#region src/cli/utils/constants.ts
43922
+ const REACT_DOCTOR_CONFIG_PROJECT_NAME = "react-doctor";
43894
43923
  const STAGED_FILES_TEMP_DIR_PREFIX = "react-doctor-staged-";
43895
43924
  const BASELINE_FILES_TEMP_DIR_PREFIX = "react-doctor-baseline-";
43896
43925
  const GH_DEFAULT_BRANCH_PROBE_TIMEOUT_MS = 5e3;
@@ -43975,7 +44004,7 @@ const makeNoopConsole = () => ({
43975
44004
  });
43976
44005
  //#endregion
43977
44006
  //#region src/cli/utils/version.ts
43978
- const VERSION = "0.5.6-dev.5b742fa";
44007
+ const VERSION = "0.5.6-dev.7d9e676";
43979
44008
  //#endregion
43980
44009
  //#region src/cli/utils/json-mode.ts
43981
44010
  let context = null;
@@ -44333,13 +44362,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
44333
44362
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
44334
44363
  * standard `SENTRY_RELEASE` override.
44335
44364
  */
44336
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.5.6-dev.5b742fa`;
44365
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.5.6-dev.7d9e676`;
44337
44366
  /**
44338
44367
  * Deployment environment shown in Sentry's environment filter. Defaults to
44339
44368
  * `production` for tagged releases and `development` for dev/unbuilt versions,
44340
44369
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
44341
44370
  */
44342
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.5.6-dev.5b742fa") ? "development" : "production");
44371
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.5.6-dev.7d9e676") ? "development" : "production");
44343
44372
  /**
44344
44373
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
44345
44374
  * (set to `0` to disable tracing) and falls back to
@@ -48600,10 +48629,9 @@ const canAnimateOnboarding = (stream = process.stdout) => {
48600
48629
  };
48601
48630
  //#endregion
48602
48631
  //#region src/cli/utils/onboarding-state.ts
48603
- const GLOBAL_CONFIG_PROJECT_NAME$2 = "react-doctor";
48604
48632
  const ONBOARDED_AT_KEY = "onboardedAt";
48605
48633
  const getOnboardingStore = (options = {}) => new Conf({
48606
- projectName: GLOBAL_CONFIG_PROJECT_NAME$2,
48634
+ projectName: REACT_DOCTOR_CONFIG_PROJECT_NAME,
48607
48635
  cwd: options.cwd
48608
48636
  });
48609
48637
  const hasCompletedOnboarding = (options = {}) => {
@@ -49897,16 +49925,7 @@ const buildHandoffPayload = (input) => {
49897
49925
  try {
49898
49926
  outputDirectory = writeDiagnosticsDirectory([...input.diagnostics], input.outputDirectory);
49899
49927
  } catch {}
49900
- const lines = [
49901
- "Before fixing anything, first ask me whether I'd like to add React Doctor to CI so every pull request is scanned automatically. Explain that:",
49902
- `- It's used by teams at ${CI_TRUST_COMPANIES}.`,
49903
- "- I don't have to fix everything at once; CI keeps new PRs clean while I incrementally pay down the existing issues.",
49904
- `- Setup guide: ${CI_URL}`,
49905
- "If I say yes, run `npx react-doctor install` (or add the GitHub Actions workflow). Either way, then continue with the fixes below.",
49906
- "",
49907
- `Fix the top ${topGroups.length} React Doctor ${topGroups.length === 1 ? "issue" : "issues"} in ${input.projectName} on this pass — leave the rest for a follow-up.`,
49908
- ""
49909
- ];
49928
+ const lines = [`Fix the top ${topGroups.length} React Doctor ${topGroups.length === 1 ? "issue" : "issues"} in ${input.projectName} on this pass — leave the rest for a follow-up.`, ""];
49910
49929
  topGroups.forEach(([ruleKey, ruleDiagnostics], index) => {
49911
49930
  const representative = ruleDiagnostics[0];
49912
49931
  const severityLabel = representative.severity === "error" ? "ERROR" : "WARN";
@@ -50276,38 +50295,52 @@ const upgradeReactDoctorWorkflowInPlace = (projectRoot) => {
50276
50295
  //#region src/cli/utils/hash-project-root.ts
50277
50296
  const hashProjectRoot = (projectRoot) => createHash("sha256").update(Path.resolve(projectRoot)).digest("hex");
50278
50297
  //#endregion
50279
- //#region src/cli/utils/action-upgrade-prompt.ts
50280
- const GLOBAL_CONFIG_PROJECT_NAME$1 = "react-doctor";
50281
- const getActionUpgradeStore = (options = {}) => new Conf({
50282
- projectName: GLOBAL_CONFIG_PROJECT_NAME$1,
50283
- cwd: options.cwd
50284
- });
50285
- const hasHandledActionUpgrade = (projectRoot, storeOptions = {}) => {
50286
- try {
50287
- const upgrades = getActionUpgradeStore(storeOptions).get("actionUpgrades", {});
50288
- return Boolean(upgrades[hashProjectRoot(projectRoot)]);
50289
- } catch {
50290
- return true;
50291
- }
50292
- };
50293
- const recordActionUpgradeDecision = (projectRoot, outcome, storeOptions = {}) => {
50294
- try {
50295
- const store = getActionUpgradeStore(storeOptions);
50296
- const upgrades = store.get("actionUpgrades", {});
50297
- store.set("actionUpgrades", {
50298
- ...upgrades,
50299
- [hashProjectRoot(projectRoot)]: {
50300
- rootDirectory: Path.resolve(projectRoot),
50301
- outcome,
50302
- at: (/* @__PURE__ */ new Date()).toISOString()
50298
+ //#region src/cli/utils/project-decision-store.ts
50299
+ const createProjectDecisionStore = (storeKey) => {
50300
+ const getStore = (options = {}) => new Conf({
50301
+ projectName: REACT_DOCTOR_CONFIG_PROJECT_NAME,
50302
+ cwd: options.cwd
50303
+ });
50304
+ return {
50305
+ getConfigPath: (options = {}) => getStore(options).path,
50306
+ hasHandled: (projectRoot, options = {}) => {
50307
+ try {
50308
+ return Boolean(getStore(options).get(storeKey, {})[hashProjectRoot(projectRoot)]);
50309
+ } catch {
50310
+ return true;
50303
50311
  }
50304
- });
50305
- return true;
50306
- } catch {
50307
- return false;
50308
- }
50312
+ },
50313
+ record: (projectRoot, outcome, options = {}) => {
50314
+ try {
50315
+ const store = getStore(options);
50316
+ store.set(storeKey, {
50317
+ ...store.get(storeKey, {}),
50318
+ [hashProjectRoot(projectRoot)]: {
50319
+ rootDirectory: Path.resolve(projectRoot),
50320
+ outcome,
50321
+ at: (/* @__PURE__ */ new Date()).toISOString()
50322
+ }
50323
+ });
50324
+ return true;
50325
+ } catch {
50326
+ return false;
50327
+ }
50328
+ }
50329
+ };
50309
50330
  };
50310
50331
  //#endregion
50332
+ //#region src/cli/utils/action-upgrade-prompt.ts
50333
+ const store$1 = createProjectDecisionStore("actionUpgrades");
50334
+ store$1.getConfigPath;
50335
+ const hasHandledActionUpgrade = store$1.hasHandled;
50336
+ const recordActionUpgradeDecision = store$1.record;
50337
+ //#endregion
50338
+ //#region src/cli/utils/ci-prompt-decision.ts
50339
+ const store = createProjectDecisionStore("ciPrompts");
50340
+ store.getConfigPath;
50341
+ const hasHandledCiPrompt = store.hasHandled;
50342
+ const recordCiPromptDecision = store.record;
50343
+ //#endregion
50311
50344
  //#region src/cli/utils/open-url.ts
50312
50345
  const resolveOpenCommand = (url) => {
50313
50346
  if (process$1.platform === "darwin") return {
@@ -51524,10 +51557,12 @@ const runInstallReactDoctor = async (options = {}) => {
51524
51557
  const existingWorkflow = readReactDoctorWorkflow(projectRoot);
51525
51558
  const canInstallWorkflow = !NFS.existsSync(workflowTargetPath);
51526
51559
  const canUpgradeWorkflow = existingWorkflow !== null && workflowUsesV1Action(existingWorkflow.content) && !hasHandledActionUpgrade(projectRoot);
51527
- const shouldInstallWorkflow = canInstallWorkflow && (Boolean(options.yes) || !skipPrompts && await askAddToGitHubActions(prompt) === "yes");
51560
+ const ciPromptOutcome = canInstallWorkflow && !options.yes && !skipPrompts && !hasHandledCiPrompt(projectRoot) ? await askAddToGitHubActions(prompt) : null;
51561
+ const shouldInstallWorkflow = canInstallWorkflow && (Boolean(options.yes) || ciPromptOutcome === "yes");
51528
51562
  const upgradePromptOutcome = canUpgradeWorkflow && !options.yes && !skipPrompts ? await askUpgradeActionVersion(prompt) : null;
51529
51563
  const shouldUpgradeWorkflow = canUpgradeWorkflow && (Boolean(options.yes) || upgradePromptOutcome === "yes");
51530
51564
  if (upgradePromptOutcome === "no" && !options.dryRun) recordActionUpgradeDecision(projectRoot, "declined");
51565
+ if ((ciPromptOutcome === "yes" || ciPromptOutcome === "no") && !options.dryRun) recordCiPromptDecision(projectRoot, ciPromptOutcome === "yes" ? "accepted" : "declined");
51531
51566
  const selectedAgents = skipPrompts ? detectedAgents : (await prompt({
51532
51567
  type: "multiselect",
51533
51568
  name: "agents",
@@ -51774,18 +51809,24 @@ const handoffToAgent = async (input) => {
51774
51809
  if (!input.interactive || input.diagnostics.length === 0) return;
51775
51810
  cliLogger.break();
51776
51811
  const projectRootForCi = findNearestPackageDirectory(input.rootDirectory) ?? input.rootDirectory;
51777
- if (!isReactDoctorWorkflowInstalled(projectRootForCi)) {
51812
+ const isGitHubActionsConfigured = isReactDoctorWorkflowInstalled(projectRootForCi);
51813
+ if (!isGitHubActionsConfigured && !hasHandledCiPrompt(projectRootForCi)) {
51778
51814
  const ciOutcome = await askAddToGitHubActions();
51779
51815
  recordCount(METRIC.agentHandoff, 1, {
51780
51816
  outcome: `ci-${ciOutcome}`,
51781
51817
  diagnosticsCount: input.diagnostics.length
51782
51818
  });
51783
51819
  if (ciOutcome === "cancel") return;
51820
+ recordCiPromptDecision(projectRootForCi, ciOutcome === "yes" ? "accepted" : "declined");
51784
51821
  if (ciOutcome === "yes") {
51785
51822
  await setUpGitHubActions({ rootDirectory: input.rootDirectory });
51786
51823
  cliLogger.break();
51787
51824
  }
51788
- } else await maybeOfferActionUpgrade(projectRootForCi);
51825
+ } else if (isGitHubActionsConfigured) await maybeOfferActionUpgrade(projectRootForCi);
51826
+ else recordCount(METRIC.agentHandoff, 1, {
51827
+ outcome: "ci-suppressed",
51828
+ diagnosticsCount: input.diagnostics.length
51829
+ });
51789
51830
  const { handoffTarget } = await prompts({
51790
51831
  type: "select",
51791
51832
  name: "handoffTarget",
@@ -52129,9 +52170,8 @@ const printMultiProjectSummary = (input) => gen(function* () {
52129
52170
  });
52130
52171
  //#endregion
52131
52172
  //#region src/cli/utils/prompt-install-setup.ts
52132
- const GLOBAL_CONFIG_PROJECT_NAME = "react-doctor";
52133
52173
  const getSetupPromptStore = (options = {}) => new Conf({
52134
- projectName: GLOBAL_CONFIG_PROJECT_NAME,
52174
+ projectName: REACT_DOCTOR_CONFIG_PROJECT_NAME,
52135
52175
  cwd: options.cwd
52136
52176
  });
52137
52177
  const getSetupPromptProjectKey = (projectRoot) => hashProjectRoot(projectRoot);
@@ -52142,6 +52182,24 @@ const hasDisabledSetupPrompt = (projectRoot, storeOptions = {}) => {
52142
52182
  return false;
52143
52183
  }
52144
52184
  };
52185
+ const disableSetupPrompt = (projectRoot, storeOptions = {}) => {
52186
+ try {
52187
+ const store = getSetupPromptStore(storeOptions);
52188
+ const projects = store.get("projects", {});
52189
+ const projectKey = getSetupPromptProjectKey(projectRoot);
52190
+ store.set("projects", {
52191
+ ...projects,
52192
+ [projectKey]: {
52193
+ ...projects[projectKey] ?? {},
52194
+ rootDirectory: Path.resolve(projectRoot),
52195
+ setupPrompt: false
52196
+ }
52197
+ });
52198
+ return true;
52199
+ } catch {
52200
+ return false;
52201
+ }
52202
+ };
52145
52203
  const resolveInstallSetupProjectRoot = (options) => {
52146
52204
  if (options.scanDirectories.length === 0) return findNearestPackageDirectory(options.scanRoot) ?? options.scanRoot;
52147
52205
  const packageDirectories = /* @__PURE__ */ new Set();
@@ -52944,6 +53002,7 @@ const inspectAction = async (directory, flags) => {
52944
53002
  })) {
52945
53003
  printAgentInstallHint();
52946
53004
  recordCount(METRIC.agentInstallHintShown, 1);
53005
+ disableSetupPrompt(setupProjectRoot);
52947
53006
  }
52948
53007
  }
52949
53008
  } catch (error) {
@@ -53951,4 +54010,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
53951
54010
  export {};
53952
54011
 
53953
54012
  //# sourceMappingURL=cli.js.map
53954
- //# debugId=54905d6a-f06f-5f80-9fb6-7d4ab857d553
54013
+ //# debugId=3622d8e5-b640-5cae-addd-2b990604cce2
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]="b4f6f7e7-99db-553a-aa15-14b646162f39")}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]="4e83db09-9255-525f-b6fd-405784826e7d")}catch(e){}}();
3
3
  import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
4
4
  import { createRequire } from "node:module";
5
5
  import * as NFS from "node:fs";
@@ -36472,15 +36472,10 @@ const buildCapabilities = (project) => {
36472
36472
  }
36473
36473
  if (project.tailwindVersion !== null) {
36474
36474
  capabilities.add("tailwind");
36475
- const tailwind = parseTailwindMajorMinor(project.tailwindVersion);
36476
- if (isTailwindAtLeast(tailwind, {
36475
+ if (isTailwindAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
36477
36476
  major: 3,
36478
36477
  minor: 4
36479
36478
  })) capabilities.add("tailwind:3.4");
36480
- if (tailwind !== null && isTailwindAtLeast(tailwind, {
36481
- major: 4,
36482
- minor: 0
36483
- })) capabilities.add("tailwind:4");
36484
36479
  }
36485
36480
  if (project.zodVersion !== null) {
36486
36481
  capabilities.add("zod");
@@ -38089,8 +38084,8 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
38089
38084
  }
38090
38085
  return enabled;
38091
38086
  };
38092
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [] }) => {
38093
- const reactHooksJsPlugin = resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
38087
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false }) => {
38088
+ const reactHooksJsPlugin = disableReactHooksJsPlugin ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
38094
38089
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
38095
38090
  const jsPlugins = [];
38096
38091
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -38787,9 +38782,9 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
38787
38782
  try {
38788
38783
  parsed = JSON.parse(sanitizedStdout);
38789
38784
  } catch {
38790
- throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 200) }) });
38785
+ throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
38791
38786
  }
38792
- if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 200) }) });
38787
+ if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
38793
38788
  const minifiedFileCache = /* @__PURE__ */ new Map();
38794
38789
  const isMinifiedDiagnosticFile = (filename) => {
38795
38790
  const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
@@ -39080,6 +39075,28 @@ const writeOxlintConfig = (configPath, configToWrite) => {
39080
39075
  NFS.closeSync(fileHandle);
39081
39076
  }
39082
39077
  };
39078
+ const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
39079
+ /**
39080
+ * Detects an oxlint config-load crash caused by the optional
39081
+ * `react-hooks-js` (eslint-plugin-react-hooks) React Compiler plugin and
39082
+ * builds the partial-failure note for it; returns `null` when the failure
39083
+ * was anything else.
39084
+ *
39085
+ * oxlint prints a framed error to stdout (not stderr) and exits non-zero
39086
+ * when a `jsPlugins` entry can't be imported; that non-JSON stdout
39087
+ * surfaces as `OxlintOutputUnparseable`. Because oxlint fails the WHOLE
39088
+ * config load on it, leaving the plugin in would drop every curated
39089
+ * react-doctor diagnostic too — so the caller retries with the plugin
39090
+ * stripped (issue #833). Both markers sit at the start of oxlint's
39091
+ * message, so they survive the `preview` slice even for deep pnpm paths.
39092
+ */
39093
+ const reactHooksJsPluginDropNote = (error) => {
39094
+ if (!(error instanceof ReactDoctorError) || error.reason._tag !== "OxlintOutputUnparseable") return null;
39095
+ const { preview } = error.reason;
39096
+ if (!preview.includes("Failed to load JS plugin") || !preview.includes("eslint-plugin-react-hooks")) return null;
39097
+ const underlyingReason = preview.match(/Error:[^\n]*/)?.[0]?.trim();
39098
+ return `${REACT_HOOKS_JS_DROP_PREFIX}${underlyingReason ? `: ${underlyingReason}` : ""}. Other rules ran normally.`;
39099
+ };
39083
39100
  /**
39084
39101
  * The oxlint runner. Composed of three pieces in `runners/oxlint/`:
39085
39102
  *
@@ -39107,15 +39124,16 @@ const runOxlint = async (options) => {
39107
39124
  const pluginPath = resolvePluginPath();
39108
39125
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
39109
39126
  const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
39110
- const buildConfig = (extendsForThisAttempt) => createOxlintConfig({
39127
+ const buildConfig = (overrides) => createOxlintConfig({
39111
39128
  pluginPath,
39112
39129
  project,
39113
39130
  customRulesOnly,
39114
- extendsPaths: extendsForThisAttempt,
39131
+ extendsPaths: overrides.extendsPaths,
39115
39132
  ignoredTags,
39116
39133
  serverAuthFunctionNames,
39117
39134
  severityControls,
39118
- userPlugins
39135
+ userPlugins,
39136
+ disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
39119
39137
  });
39120
39138
  const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
39121
39139
  const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
@@ -39151,12 +39169,22 @@ const runOxlint = async (options) => {
39151
39169
  outputMaxBytes,
39152
39170
  concurrency: options.concurrency
39153
39171
  });
39154
- writeOxlintConfig(configPath, buildConfig(extendsPaths));
39172
+ writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
39155
39173
  try {
39156
39174
  return await runBatches();
39157
39175
  } catch (error) {
39176
+ const reactHooksJsDropNote = reactHooksJsPluginDropNote(error);
39177
+ if (reactHooksJsDropNote !== null) {
39178
+ writeOxlintConfig(configPath, buildConfig({
39179
+ extendsPaths,
39180
+ disableReactHooksJsPlugin: true
39181
+ }));
39182
+ const diagnostics = await runBatches();
39183
+ onPartialFailure?.(reactHooksJsDropNote);
39184
+ return diagnostics;
39185
+ }
39158
39186
  if (extendsPaths.length === 0) throw error;
39159
- writeOxlintConfig(configPath, buildConfig([]));
39187
+ writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
39160
39188
  return await runBatches();
39161
39189
  }
39162
39190
  } finally {
@@ -40576,4 +40604,4 @@ const toJsonReport = (result, options) => buildJsonReport({
40576
40604
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
40577
40605
 
40578
40606
  //# sourceMappingURL=index.js.map
40579
- //# debugId=b4f6f7e7-99db-553a-aa15-14b646162f39
40607
+ //# debugId=4e83db09-9255-525f-b6fd-405784826e7d
package/dist/lsp.js CHANGED
@@ -36458,15 +36458,10 @@ const buildCapabilities = (project) => {
36458
36458
  }
36459
36459
  if (project.tailwindVersion !== null) {
36460
36460
  capabilities.add("tailwind");
36461
- const tailwind = parseTailwindMajorMinor(project.tailwindVersion);
36462
- if (isTailwindAtLeast(tailwind, {
36461
+ if (isTailwindAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
36463
36462
  major: 3,
36464
36463
  minor: 4
36465
36464
  })) capabilities.add("tailwind:3.4");
36466
- if (tailwind !== null && isTailwindAtLeast(tailwind, {
36467
- major: 4,
36468
- minor: 0
36469
- })) capabilities.add("tailwind:4");
36470
36465
  }
36471
36466
  if (project.zodVersion !== null) {
36472
36467
  capabilities.add("zod");
@@ -38075,8 +38070,8 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
38075
38070
  }
38076
38071
  return enabled;
38077
38072
  };
38078
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [] }) => {
38079
- const reactHooksJsPlugin = resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
38073
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false }) => {
38074
+ const reactHooksJsPlugin = disableReactHooksJsPlugin ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
38080
38075
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
38081
38076
  const jsPlugins = [];
38082
38077
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -38773,9 +38768,9 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
38773
38768
  try {
38774
38769
  parsed = JSON.parse(sanitizedStdout);
38775
38770
  } catch {
38776
- throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 200) }) });
38771
+ throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
38777
38772
  }
38778
- if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 200) }) });
38773
+ if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
38779
38774
  const minifiedFileCache = /* @__PURE__ */ new Map();
38780
38775
  const isMinifiedDiagnosticFile = (filename) => {
38781
38776
  const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
@@ -39066,6 +39061,28 @@ const writeOxlintConfig = (configPath, configToWrite) => {
39066
39061
  NFS.closeSync(fileHandle);
39067
39062
  }
39068
39063
  };
39064
+ const REACT_HOOKS_JS_DROP_PREFIX = "React Compiler rules (react-hooks-js/*) skipped — eslint-plugin-react-hooks failed to load in this environment";
39065
+ /**
39066
+ * Detects an oxlint config-load crash caused by the optional
39067
+ * `react-hooks-js` (eslint-plugin-react-hooks) React Compiler plugin and
39068
+ * builds the partial-failure note for it; returns `null` when the failure
39069
+ * was anything else.
39070
+ *
39071
+ * oxlint prints a framed error to stdout (not stderr) and exits non-zero
39072
+ * when a `jsPlugins` entry can't be imported; that non-JSON stdout
39073
+ * surfaces as `OxlintOutputUnparseable`. Because oxlint fails the WHOLE
39074
+ * config load on it, leaving the plugin in would drop every curated
39075
+ * react-doctor diagnostic too — so the caller retries with the plugin
39076
+ * stripped (issue #833). Both markers sit at the start of oxlint's
39077
+ * message, so they survive the `preview` slice even for deep pnpm paths.
39078
+ */
39079
+ const reactHooksJsPluginDropNote = (error) => {
39080
+ if (!(error instanceof ReactDoctorError) || error.reason._tag !== "OxlintOutputUnparseable") return null;
39081
+ const { preview } = error.reason;
39082
+ if (!preview.includes("Failed to load JS plugin") || !preview.includes("eslint-plugin-react-hooks")) return null;
39083
+ const underlyingReason = preview.match(/Error:[^\n]*/)?.[0]?.trim();
39084
+ return `${REACT_HOOKS_JS_DROP_PREFIX}${underlyingReason ? `: ${underlyingReason}` : ""}. Other rules ran normally.`;
39085
+ };
39069
39086
  /**
39070
39087
  * The oxlint runner. Composed of three pieces in `runners/oxlint/`:
39071
39088
  *
@@ -39093,15 +39110,16 @@ const runOxlint = async (options) => {
39093
39110
  const pluginPath = resolvePluginPath();
39094
39111
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
39095
39112
  const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
39096
- const buildConfig = (extendsForThisAttempt) => createOxlintConfig({
39113
+ const buildConfig = (overrides) => createOxlintConfig({
39097
39114
  pluginPath,
39098
39115
  project,
39099
39116
  customRulesOnly,
39100
- extendsPaths: extendsForThisAttempt,
39117
+ extendsPaths: overrides.extendsPaths,
39101
39118
  ignoredTags,
39102
39119
  serverAuthFunctionNames,
39103
39120
  severityControls,
39104
- userPlugins
39121
+ userPlugins,
39122
+ disableReactHooksJsPlugin: overrides.disableReactHooksJsPlugin
39105
39123
  });
39106
39124
  const restoreDisableDirectives = respectInlineDisables ? () => {} : await neutralizeDisableDirectives(rootDirectory, includePaths);
39107
39125
  const configDirectory = NFS.mkdtempSync(Path.join(os.tmpdir(), "react-doctor-oxlintrc-"));
@@ -39137,12 +39155,22 @@ const runOxlint = async (options) => {
39137
39155
  outputMaxBytes,
39138
39156
  concurrency: options.concurrency
39139
39157
  });
39140
- writeOxlintConfig(configPath, buildConfig(extendsPaths));
39158
+ writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
39141
39159
  try {
39142
39160
  return await runBatches();
39143
39161
  } catch (error) {
39162
+ const reactHooksJsDropNote = reactHooksJsPluginDropNote(error);
39163
+ if (reactHooksJsDropNote !== null) {
39164
+ writeOxlintConfig(configPath, buildConfig({
39165
+ extendsPaths,
39166
+ disableReactHooksJsPlugin: true
39167
+ }));
39168
+ const diagnostics = await runBatches();
39169
+ onPartialFailure?.(reactHooksJsDropNote);
39170
+ return diagnostics;
39171
+ }
39144
39172
  if (extendsPaths.length === 0) throw error;
39145
- writeOxlintConfig(configPath, buildConfig([]));
39173
+ writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
39146
39174
  return await runBatches();
39147
39175
  }
39148
39176
  } finally {
@@ -42361,5 +42389,5 @@ const startLanguageServer = () => {
42361
42389
  };
42362
42390
  //#endregion
42363
42391
  export { startLanguageServer };
42364
- !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]="9421149c-0ed9-5e00-81da-4f7dd8faf332")}catch(e){}}();
42365
- //# debugId=9421149c-0ed9-5e00-81da-4f7dd8faf332
42392
+ !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]="7deadb2d-94c2-54e2-bd0d-808ee8d4c380")}catch(e){}}();
42393
+ //# debugId=7deadb2d-94c2-54e2-bd0d-808ee8d4c380
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.5.6-dev.5b742fa",
3
+ "version": "0.5.6-dev.7d9e676",
4
4
  "description": "Your agent writes bad React. This catches it",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -64,7 +64,7 @@
64
64
  "vscode-languageserver": "^9.0.1",
65
65
  "vscode-languageserver-textdocument": "^1.0.12",
66
66
  "vscode-uri": "^3.1.0",
67
- "oxlint-plugin-react-doctor": "0.5.6-dev.5b742fa"
67
+ "oxlint-plugin-react-doctor": "0.5.6-dev.7d9e676"
68
68
  },
69
69
  "devDependencies": {
70
70
  "@types/babel__code-frame": "^7.27.0",
@@ -73,8 +73,8 @@
73
73
  "commander": "^14.0.3",
74
74
  "ora": "^9.4.0",
75
75
  "@react-doctor/api": "0.5.6",
76
- "@react-doctor/language-server": "0.5.6",
77
- "@react-doctor/core": "0.5.6"
76
+ "@react-doctor/core": "0.5.6",
77
+ "@react-doctor/language-server": "0.5.6"
78
78
  },
79
79
  "engines": {
80
80
  "node": "^20.19.0 || >=22.13.0"