// src/actions/lintlint.ts
import {
  existsSync as existsSync3,
  mkdtempSync,
  readFileSync as readFileSync3,
  rmSync,
  writeFileSync
} from "node:fs";
import os from "node:os";
import PATH5 from "node:path";
import chalk5 from "chalk";
import { findUp } from "find-up";

// src/lib/crossSpawn.ts
import crossSpawn from "cross-spawn";
function spawnSync(command, args, options) {
  return crossSpawn.sync(command, args, options);
}

// src/lib/packageManagerRuntime.ts
import fs from "node:fs";
import chalk from "chalk";
var DISPLAY_NAMES = {
  bun: "Bun",
  npm: "npm",
  pnpm: "pnpm",
  yarn: "Yarn"
};
var MAC_INSTALL_COMMANDS = {
  bun: "brew install oven-sh/bun/bun",
  npm: "brew install node",
  pnpm: "brew install pnpm",
  yarn: "brew install yarn"
};
var SUPPORTED_PLATFORMS = ["darwin", "linux", "win32"];
function currentPlatform() {
  return SUPPORTED_PLATFORMS.find((platform) => platform === process.platform) ?? "unknown";
}
function shouldAskYesNo(question) {
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
    return false;
  }
  process.stdout.write(question);
  const buffer = Buffer.alloc(1024);
  const bytesRead = fs.readSync(process.stdin.fd, buffer, 0, buffer.length, null);
  const answer = buffer.toString("utf8", 0, bytesRead).trim().toLowerCase();
  return answer === "y" || answer === "yes";
}
function isCommandInstalled(command) {
  const result = spawnSync(command, ["--version"], {
    encoding: "utf8",
    stdio: "ignore"
  });
  return !result.error && result.status === 0;
}
function isPackageManagerInstalled(pm) {
  return isCommandInstalled(pm);
}
function getPackageManagerInstallPlan(pm, platform = currentPlatform()) {
  const displayName = DISPLAY_NAMES[pm];
  if (platform === "darwin") {
    const command = MAC_INSTALL_COMMANDS[pm];
    return {
      command,
      manualInstructions: [
        `Install ${displayName} with: ${command}`
      ],
      packageManager: pm,
      platform,
      supported: true
    };
  }
  if (platform === "linux") {
    return {
      manualInstructions: [
        `Automatic installation for ${displayName} is not implemented on Linux yet.`,
        `Install ${displayName} manually and re-run the command.`
      ],
      packageManager: pm,
      platform,
      supported: false
    };
  }
  if (platform === "win32") {
    return {
      manualInstructions: [
        `Automatic installation for ${displayName} is not implemented on Windows yet.`,
        `Install ${displayName} manually and re-run the command.`
      ],
      packageManager: pm,
      platform,
      supported: false
    };
  }
  return {
    manualInstructions: [
      `Automatic installation for ${displayName} is not implemented on ${platform} yet.`,
      `Install ${displayName} manually and re-run the command.`
    ],
    packageManager: pm,
    platform,
    supported: false
  };
}
function printManualInstructions(plan, context) {
  console.error(chalk.yellow(`${DISPLAY_NAMES[plan.packageManager]} is required for "${context.operation}".`));
  for (const line of plan.manualInstructions) {
    console.error(chalk.gray(`  ${line}`));
  }
}
function shouldInstallWithHomebrew(pm, cwd) {
  const command = MAC_INSTALL_COMMANDS[pm];
  const result = spawnSync("brew", command.replace("brew ", "").split(" "), {
    cwd,
    encoding: "utf8",
    stdio: "inherit"
  });
  return result.status === 0;
}
function didEnsurePackageManagerInstalled(pm, context) {
  if (isPackageManagerInstalled(pm)) return true;
  const plan = getPackageManagerInstallPlan(pm, context.platform ?? currentPlatform());
  const displayName = DISPLAY_NAMES[pm];
  console.error(chalk.yellow(`${context.operation} requires ${displayName}, but it is not installed.`));
  if (!plan.supported) {
    printManualInstructions(plan, context);
    return false;
  }
  if (!isCommandInstalled("brew")) {
    console.error(chalk.yellow("Homebrew is not installed, so automatic installation is unavailable."));
    console.error(chalk.gray("  Install Homebrew from https://brew.sh and then run:"));
    console.error(chalk.gray(`  ${plan.command}`));
    return false;
  }
  const isConfirmed = shouldAskYesNo(chalk.cyan(`Install ${displayName} with Homebrew now? [y/N] `));
  if (!isConfirmed) {
    console.error(chalk.gray(`Skipping install. Run "${plan.command}" manually and then retry.`));
    return false;
  }
  console.error(chalk.cyan(`Installing ${displayName} via Homebrew...
`));
  if (!shouldInstallWithHomebrew(pm, context.cwd)) {
    console.error(chalk.red(`Homebrew failed to install ${displayName}.`));
    console.error(chalk.gray(`Run "${plan.command}" manually and then retry.`));
    return false;
  }
  if (!isPackageManagerInstalled(pm)) {
    console.error(chalk.red(`${displayName} still does not appear to be installed after Homebrew completed.`));
    console.error(chalk.gray(`Run "${plan.command}" manually and then retry.`));
    return false;
  }
  console.error(chalk.green(`${displayName} installed successfully.`));
  return true;
}
function failureResult() {
  return {
    output: ["", ""],
    pid: 0,
    signal: null,
    status: 1,
    stderr: "",
    stdout: ""
  };
}
function spawnPackageManagerSync(pm, args, options) {
  if (!didEnsurePackageManagerInstalled(pm, options.context)) {
    return failureResult();
  }
  return spawnSync(pm, args, { encoding: "utf8", ...options });
}

// src/pm/workspaces.ts
import { existsSync, readFileSync } from "node:fs";
import PATH from "node:path";
import { globSync } from "glob";
function readJsonFile(path2) {
  if (!existsSync(path2)) return void 0;
  try {
    return JSON.parse(readFileSync(path2, "utf8"));
  } catch {
    return void 0;
  }
}
function readRootPackageJson(cwd = process.cwd()) {
  return readJsonFile(PATH.resolve(cwd, "package.json"));
}
function detectPackageManagerFromPackageJson(cwd = process.cwd()) {
  const packageManager = readRootPackageJson(cwd)?.packageManager;
  if (!(packageManager != null && packageManager.length > 0)) return void 0;
  return packageManager.split("@", 1)[0];
}

// src/pm/detectPackageManager.ts
import { existsSync as existsSync2 } from "node:fs";
var knownPackageManagers = /* @__PURE__ */ new Set(["bun", "npm", "pnpm", "yarn"]);
function detectPackageManager() {
  const packageManager = detectPackageManagerFromPackageJson();
  if (packageManager != null && packageManager.length > 0 && knownPackageManagers.has(packageManager)) {
    return packageManager;
  }
  if (existsSync2("pnpm-lock.yaml") || existsSync2("pnpm-workspace.yaml")) return "pnpm";
  if (existsSync2("bun.lock") || existsSync2("bun.lockb")) return "bun";
  if (existsSync2("yarn.lock") || existsSync2(".yarnrc.yml")) return "yarn";
  if (existsSync2("package-lock.json") || existsSync2("npm-shrinkwrap.json")) return "npm";
  return "yarn";
}

// src/pm/isReactProject.ts
import { readFileSync as readFileSync2 } from "node:fs";
import PATH2 from "node:path";
import chalk2 from "chalk";
import { globSync as globSync2 } from "glob";
function hasReactDependency(packageJsonPath) {
  try {
    const content = readFileSync2(packageJsonPath, "utf8");
    const pkg = JSON.parse(content);
    const allDeps = {
      ...pkg.dependencies,
      ...pkg.devDependencies,
      ...pkg.peerDependencies
    };
    return Object.hasOwn(allDeps, "react") || Object.hasOwn(allDeps, "react-dom");
  } catch {
    return false;
  }
}
function isReactInMonorepo(cwd, isVerbose) {
  const rootPkgPath = PATH2.resolve(cwd, "package.json");
  if (hasReactDependency(rootPkgPath)) {
    if (isVerbose === true) console.log(chalk2.gray("  React detected in package.json"));
    return true;
  }
  const packageJsonPaths = globSync2("packages/**/package.json", {
    cwd,
    ignore: ["**/node_modules/**"]
  });
  for (const relPath of packageJsonPaths) {
    const fullPath = PATH2.resolve(cwd, relPath);
    if (hasReactDependency(fullPath)) {
      if (isVerbose === true) console.log(chalk2.gray(`  React detected in ${relPath}`));
      return true;
    }
  }
  return false;
}

// src/lib/reporting/xyReporter.ts
var reporterState = {
  currentCommand: "unknown",
  isEnvelopeEmitted: false,
  isJsonModeEnabled: false,
  isStrictModeEnabled: false,
  originalStdoutWrite: void 0,
  startTime: 0
};
function isStrictMode() {
  return reporterState.isStrictModeEnabled || process.env.XY_STRICT === "1";
}

// src/lib/shouldRunInstall.ts
import chalk3 from "chalk";
function shouldRunInstall(cwd) {
  const pm = detectPackageManager();
  console.log(chalk3.gray(`Running ${pm} install...`));
  const result = spawnPackageManagerSync(pm, ["install"], {
    context: { cwd, operation: `Run ${pm} install` },
    cwd,
    encoding: "utf8",
    stdio: "inherit"
  });
  if (result.status !== 0) {
    console.warn(chalk3.yellow(`${pm} install failed`));
    return false;
  }
  console.log(chalk3.green("Dependencies installed"));
  return true;
}

// src/actions/dead/runtimeEntries.ts
import fs2 from "node:fs";
import path from "node:path";
var codeExtensionRe = /\.(?:ts|tsx|mts|cts|js|mjs|cjs)$/i;
var resolutionExtensions = [".mjs", ".cjs", ".js", ".d.mts", ".d.cts", ".d.ts", ".mts", ".cts", ".ts", ".tsx"];
function readPackageManifest(location) {
  try {
    return JSON.parse(fs2.readFileSync(path.join(location, "package.json"), "utf8"));
  } catch {
    return void 0;
  }
}
function collectExportTargets(value) {
  if (typeof value === "string") return value.startsWith("./") ? [value] : [];
  if (Array.isArray(value)) return value.flatMap(collectExportTargets);
  if (typeof value !== "object" || value === null) return [];
  return Object.values(value).flatMap(collectExportTargets);
}
function resolveCodeFile(filePath) {
  if (fs2.existsSync(filePath) && codeExtensionRe.test(filePath)) return filePath;
  const ext = path.extname(filePath);
  if (ext) {
    const withoutExt = filePath.slice(0, -ext.length);
    for (const candidateExt of resolutionExtensions) {
      const candidate = `${withoutExt}${candidateExt}`;
      if (fs2.existsSync(candidate)) return candidate;
    }
  }
  for (const candidateExt of resolutionExtensions) {
    const candidate = `${filePath}${candidateExt}`;
    if (fs2.existsSync(candidate)) return candidate;
  }
  for (const candidateExt of resolutionExtensions) {
    const candidate = path.join(filePath, `index${candidateExt}`);
    if (fs2.existsSync(candidate)) return candidate;
  }
  return void 0;
}
function resolveManifestEntry(location, entry) {
  if (path.isAbsolute(entry)) return void 0;
  if (entry.includes("*")) return void 0;
  const relativeEntry = entry.startsWith(".") ? entry : `./${entry}`;
  return resolveCodeFile(path.resolve(location, relativeEntry));
}
function getRuntimeRootFiles(location, manifest) {
  if (!manifest) return [];
  const candidates = [
    ...collectExportTargets(manifest.exports),
    manifest.main,
    manifest.module,
    manifest.types,
    manifest.typings
  ].filter((entry) => typeof entry === "string");
  const bin = manifest.bin;
  if (bin !== void 0) {
    if (typeof bin === "string") candidates.push(bin);
    else for (const value of Object.values(bin)) if (typeof value === "string") candidates.push(value);
  }
  const seen = /* @__PURE__ */ new Set();
  const results = [];
  for (const entry of candidates) {
    const resolved = resolveManifestEntry(location, entry);
    if (!(resolved != null && resolved.length > 0) || seen.has(resolved)) continue;
    const distMapped = mapDistToSrc(location, resolved);
    const final = distMapped ?? resolved;
    if (seen.has(final)) continue;
    seen.add(final);
    results.push(final);
  }
  return results;
}
function mapDistToSrc(location, file) {
  const rel = path.relative(location, file);
  if (!rel.startsWith("dist" + path.sep) && !rel.startsWith("dist/")) return void 0;
  const tail = rel.slice("dist".length).replace(/^[\\/]/, "");
  const tailNoExt = tail.replace(/\.(?:mjs|cjs|js|d\.mts|d\.cts|d\.ts)$/i, "");
  const candidates = [
    path.join(location, "src", tailNoExt),
    path.join(location, "src", tailNoExt + ".ts"),
    path.join(location, "src", tailNoExt + ".tsx"),
    path.join(location, "src", tailNoExt + ".mts"),
    path.join(location, "src", tailNoExt + ".cts")
  ];
  for (const candidate of candidates) {
    const resolved = resolveCodeFile(candidate);
    if (resolved != null && resolved.length > 0) return resolved;
  }
  return void 0;
}

// src/actions/barrel/getReExportSpecs.ts
import fs3 from "node:fs";
import PATH3 from "node:path";
import ts from "typescript";

// src/actions/deplint/getBasePackageName.ts
function getBasePackageName(importName) {
  const importNameScrubbed = importName.replaceAll('"', "").trim();
  if (importNameScrubbed.startsWith("@")) {
    const parts = importNameScrubbed.split("/");
    return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : importNameScrubbed;
  }
  return importNameScrubbed.split("/", 1)[0];
}

// src/actions/barrel/getReExportSpecs.ts
function getReExportSpecs(file) {
  let sourceText;
  try {
    sourceText = fs3.readFileSync(file, "utf8");
  } catch {
    return [];
  }
  const isJsLike = /\.(?:js|mjs|cjs)$/i.test(file);
  const sourceFile = ts.createSourceFile(
    PATH3.basename(file),
    sourceText,
    ts.ScriptTarget.Latest,
    true,
    isJsLike ? ts.ScriptKind.JS : void 0
  );
  const specs = /* @__PURE__ */ new Set();
  function visit(node) {
    if (ts.isExportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {
      const spec = node.moduleSpecifier.text;
      if (!spec.startsWith(".") && !spec.startsWith("node:")) {
        specs.add(getBasePackageName(spec));
      }
    }
    ts.forEachChild(node, visit);
  }
  visit(sourceFile);
  return [...specs];
}

// src/actions/barrel/resolveBarrel.ts
import fs4 from "node:fs";
import { createRequire } from "node:module";
import PATH4 from "node:path";
var require2 = createRequire(import.meta.url);
function findPackageRoot(entry, pkg) {
  let dir = PATH4.dirname(entry);
  for (; ; ) {
    const manifestPath = PATH4.join(dir, "package.json");
    if (fs4.existsSync(manifestPath)) {
      try {
        const manifest = JSON.parse(fs4.readFileSync(manifestPath, "utf8"));
        if (manifest.name === pkg) return dir;
      } catch {
      }
    }
    const parent = PATH4.dirname(dir);
    if (parent === dir) return void 0;
    dir = parent;
  }
}
function resolvePackageDir(pkg, fromDir) {
  try {
    return PATH4.dirname(require2.resolve(`${pkg}/package.json`, { paths: [fromDir] }));
  } catch {
  }
  try {
    const entry = require2.resolve(pkg, { paths: [fromDir] });
    return findPackageRoot(entry, pkg);
  } catch {
    return void 0;
  }
}

// src/actions/barrel/analyzeBarrel.ts
function analyzeBarrel(barrelPkg, fromDir, scopePrefix) {
  const collected = /* @__PURE__ */ new Set();
  const visited = /* @__PURE__ */ new Set();
  const queue = [{ fromDir, pkg: barrelPkg }];
  while (queue.length > 0) {
    const current = queue.shift();
    if (!current || visited.has(current.pkg)) continue;
    visited.add(current.pkg);
    const location = resolvePackageDir(current.pkg, current.fromDir);
    if (!(location != null && location.length > 0)) continue;
    const roots = getRuntimeRootFiles(location, readPackageManifest(location));
    const specs = /* @__PURE__ */ new Set();
    for (const root of roots) {
      for (const spec of getReExportSpecs(root)) specs.add(spec);
    }
    const eligibleSpecs = [...specs].filter(
      (spec) => spec !== barrelPkg && (!(scopePrefix != null && scopePrefix.length > 0) || spec.startsWith(scopePrefix))
    );
    for (const spec of eligibleSpecs) {
      collected.add(spec);
      if (!visited.has(spec)) queue.push({ fromDir: location, pkg: spec });
    }
  }
  collected.delete(barrelPkg);
  return [...collected].toSorted((a, b) => a.localeCompare(b));
}

// src/actions/lint-init.ts
import chalk4 from "chalk";
function defaultBarrelMessage(pkg) {
  return `Use '${pkg}' instead.`;
}
var BARREL_DESCRIPTORS = [
  {
    barrelType: "js",
    configVarName: "disallowedImportsXyLabs",
    message: defaultBarrelMessage("@xylabs/sdk-js"),
    pkg: "@xylabs/sdk-js",
    scopePrefix: "@xylabs/"
  },
  {
    barrelType: "js",
    configVarName: "disallowedImportsXyo",
    message: defaultBarrelMessage("@xyo-network/sdk-js"),
    pkg: "@xyo-network/sdk-js",
    scopePrefix: "@xyo-network/"
  },
  {
    barrelType: "isReact",
    configVarName: "disallowedImportsXyLabsReact",
    message: defaultBarrelMessage("@xylabs/sdk-isReact"),
    pkg: "@xylabs/sdk-isReact",
    scopePrefix: "@xylabs/"
  }
];
function formatDisallowedArray(name, imports, message) {
  const items = imports.map((i) => `  { name: '${i}', message: "${message}" },`).join("\n");
  return `const ${name} = [
${items}
]`;
}

// src/actions/lintlint.ts
function parseRuleValue(value) {
  if (typeof value === "string") {
    return { level: value };
  }
  if (typeof value === "number") {
    return { level: String(value) };
  }
  if (Array.isArray(value) && value.length > 0) {
    return {
      level: String(value[0]),
      options: value.length > 1 ? value.slice(1) : void 0
    };
  }
  return void 0;
}
function normalizeLevel(level) {
  if (level === "0" || level === "off") return "off";
  if (level === "1" || level === "warn") return "warn";
  if (level === "2" || level === "error") return "error";
  return level;
}
function isRulesMatching(a, b) {
  if (normalizeLevel(a.level) !== normalizeLevel(b.level)) return false;
  return JSON.stringify(a.options) === JSON.stringify(b.options);
}
function formatRule(entry) {
  if (entry.options) {
    return JSON.stringify([entry.level, ...entry.options]);
  }
  return JSON.stringify([entry.level]);
}
function mergeRulesFromBlocks(blocks) {
  const merged = /* @__PURE__ */ new Map();
  for (const block of blocks) {
    if (!block.rules) continue;
    for (const [name, value] of Object.entries(block.rules)) {
      const parsed = parseRuleValue(value);
      if (parsed) merged.set(name, parsed);
    }
  }
  return merged;
}
function detectSharedPackage(source) {
  if (source.includes("@xylabs/eslint-config-react-flat")) return "@xylabs/eslint-config-react-flat";
  if (source.includes("@xylabs/eslint-config-flat")) return "@xylabs/eslint-config-flat";
  return void 0;
}
function extractLocalRuleBlocks(source) {
  const blocks = [];
  const ruleBlockRegex = /\{\s*(?:files\s*:\s*\[.*?\]\s*,\s*)?rules\s*:\s*\{([^}]*(?:\{[^}]*\}[^}]*)*)\}/g;
  let match;
  while ((match = ruleBlockRegex.exec(source)) !== null) {
    blocks.push(match[1]);
  }
  return blocks;
}
function extractRulesFromSourceBlocks(blocks) {
  const rules = /* @__PURE__ */ new Map();
  for (const block of blocks) {
    const ruleRegex = /['"]([^'"]+)['"]\s*:\s*(\[[\s\S]*?\](?=\s*,|\s*$))/gm;
    let match;
    while ((match = ruleRegex.exec(block)) !== null) {
      rules.set(match[1], match[2]);
    }
  }
  return rules;
}
function extractConfigBlocks(sharedModule) {
  const config = sharedModule.config ?? sharedModule.default;
  if (Array.isArray(config)) return config;
  return [];
}
async function resolveSharedConfig(configDir, sharedPkg) {
  try {
    const sharedModule = await import(sharedPkg);
    return extractConfigBlocks(sharedModule);
  } catch {
    const distPath = PATH5.resolve(configDir, "node_modules", sharedPkg, "dist", "node", "index.mjs");
    try {
      const sharedModule = await import(distPath);
      return extractConfigBlocks(sharedModule);
    } catch {
      const neutralPath = PATH5.resolve(configDir, "node_modules", sharedPkg, "dist", "neutral", "index.mjs");
      const sharedModule = await import(neutralPath);
      return extractConfigBlocks(sharedModule);
    }
  }
}
async function loadSharedRules(configDir, sharedPkg, isVerbose) {
  const sharedBlocks = await resolveSharedConfig(configDir, sharedPkg);
  const sharedRules = mergeRulesFromBlocks(sharedBlocks);
  if (isVerbose) {
    console.log(chalk5.gray(`Shared config defines ${sharedRules.size} rules`));
  }
  if (sharedRules.size === 0) {
    console.error(chalk5.red("Could not load rules from shared config. Is it installed and built?"));
    return void 0;
  }
  return sharedRules;
}
async function loadLocalRules(eslintConfigPath, source, isVerbose) {
  const localModule = await import(eslintConfigPath);
  const localConfig = localModule.default ?? localModule;
  const localBlocks = Array.isArray(localConfig) ? localConfig : [localConfig];
  const resolved = mergeRulesFromBlocks(localBlocks);
  const localRuleBlocks = extractLocalRuleBlocks(source);
  const explicit = extractRulesFromSourceBlocks(localRuleBlocks);
  if (isVerbose) {
    console.log(chalk5.gray(`Local config has ${explicit.size} explicit rule setting(s)`));
  }
  return { explicit, resolved };
}
var BARREL_RESTRICTION_MESSAGES = new Set(BARREL_DESCRIPTORS.map((descriptor) => descriptor.message));
function isLintInitBarrelRestriction(ruleName, local) {
  if (ruleName !== "no-restricted-imports") return false;
  const paths = extractRestrictedPaths(local);
  if (paths.length === 0) return false;
  return paths.every((path2) => BARREL_RESTRICTION_MESSAGES.has(path2.message ?? ""));
}
function compareRules(explicitRuleNames, allResolvedRules, sharedRules) {
  const redundant = [];
  const overrides = [];
  const additions = [];
  for (const ruleName of explicitRuleNames.keys()) {
    const resolvedEntry = allResolvedRules.get(ruleName);
    if (!resolvedEntry) continue;
    const sharedEntry = sharedRules.get(ruleName);
    if (!sharedEntry) {
      additions.push({ local: resolvedEntry, rule: ruleName });
    } else if (isRulesMatching(resolvedEntry, sharedEntry)) {
      redundant.push({
        local: resolvedEntry,
        rule: ruleName,
        shared: sharedEntry
      });
    } else if (isLintInitBarrelRestriction(ruleName, resolvedEntry)) {
    } else {
      overrides.push({
        local: resolvedEntry,
        rule: ruleName,
        shared: sharedEntry
      });
    }
  }
  return {
    additions,
    overrides,
    redundant
  };
}
function reportResults({
  additions,
  overrides,
  redundant
}, isVerbose) {
  if (redundant.length > 0) {
    console.log(chalk5.yellow(`
${redundant.length} redundant rule(s) (same as shared config \u2014 can be removed):`));
    for (const { rule, local } of redundant) {
      console.log(chalk5.yellow(`  ${rule}: ${formatRule(local)}`));
    }
  }
  if (overrides.length > 0) {
    console.log(chalk5.cyan(`
${overrides.length} rule override(s) (different from shared config):`));
    for (const {
      rule,
      local,
      shared
    } of overrides) {
      console.log(chalk5.cyan(`  ${rule}:`));
      console.log(chalk5.gray(`    shared: ${formatRule(shared)}`));
      console.log(chalk5.white(`    local:  ${formatRule(local)}`));
    }
  }
  if (additions.length > 0 && isVerbose) {
    console.log(chalk5.gray(`
${additions.length} local addition(s) (not in shared config):`));
    for (const { rule, local } of additions) {
      console.log(chalk5.gray(`  ${rule}: ${formatRule(local)}`));
    }
  }
  if (redundant.length === 0 && overrides.length === 0) {
    console.log(chalk5.green("No redundant or overridden rules found"));
  }
}
function fixRedundantRules(eslintConfigPath, redundant) {
  let updated = readFileSync3(eslintConfigPath, "utf8");
  const original = updated;
  for (const { rule } of redundant) {
    const escaped = rule.replaceAll("/", String.raw`\/`);
    const pattern = new RegExp(String.raw`[ \t]*['"]${escaped}['"]\s*:\s*\[[^\]]*\],?[ \t]*\n?`, "g");
    updated = updated.replace(pattern, "");
  }
  updated = updated.replaceAll(/\{\s*rules\s*:\s*\{\s*\}\s*,?\s*\}\s*,?/g, "");
  updated = updated.replaceAll(/\n{3,}/g, "\n\n");
  if (updated !== original) {
    writeFileSync(eslintConfigPath, updated, "utf8");
    console.log(chalk5.green(`
Fixed: removed ${redundant.length} redundant rule(s)`));
  }
}
function formatConfigFile(eslintConfigPath) {
  spawnSync("eslint", ["--shouldFix", eslintConfigPath], { stdio: "inherit" });
}
function fixConfigMismatch(eslintConfigPath, configDir, source, sharedPkg, expectedPkg) {
  const updated = source.replaceAll(sharedPkg, () => expectedPkg);
  writeFileSync(eslintConfigPath, updated, "utf8");
  console.log(chalk5.green(`Fixed: replaced ${sharedPkg} with ${expectedPkg}`));
  const packageJsonPath = PATH5.resolve(configDir, "package.json");
  if (!existsSync3(packageJsonPath)) return;
  const content = readFileSync3(packageJsonPath, "utf8");
  const pkg = JSON.parse(content);
  const devDeps = pkg.devDependencies ?? {};
  const oldVersion = devDeps[sharedPkg];
  if (!oldVersion) return;
  delete devDeps[sharedPkg];
  devDeps[expectedPkg] = oldVersion;
  const sorted = Object.fromEntries(Object.entries(devDeps).toSorted(([a], [b]) => a.localeCompare(b)));
  pkg.devDependencies = sorted;
  writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}
`, "utf8");
  console.log(chalk5.green(`Updated package.json: ${sharedPkg} \u2192 ${expectedPkg}`));
  shouldRunInstall(configDir);
}
function shouldCheckConfigVariant(eslintConfigPath, configDir, source, sharedPkg, shouldFix, isVerbose) {
  const hasReact = isReactInMonorepo(configDir, isVerbose);
  const expectedPkg = hasReact ? "@xylabs/eslint-config-react-flat" : "@xylabs/eslint-config-flat";
  if (sharedPkg === expectedPkg) return false;
  console.log(chalk5.yellow(`
Config mismatch: using ${sharedPkg} but ${hasReact ? "React packages detected" : "no React packages found"}`));
  console.log(chalk5.yellow(`  Expected: ${expectedPkg}`));
  if (shouldFix) {
    fixConfigMismatch(eslintConfigPath, configDir, source, sharedPkg, expectedPkg);
  }
  return true;
}
function isRestrictedPath(value) {
  return typeof value === "object" && value !== null && typeof value.name === "string";
}
function extractRestrictedPaths(entry) {
  if (!entry?.options) return [];
  for (const option of entry.options) {
    if (typeof option === "object" && option !== null && "paths" in option) {
      const paths = option.paths;
      if (Array.isArray(paths)) return paths.filter(isRestrictedPath);
    }
  }
  return [];
}
function ensureBarrelForAnalysis(configDir, pkg, tempDirs, isVerbose) {
  const localPackageDir = resolvePackageDir(pkg, configDir);
  if (localPackageDir !== void 0 && localPackageDir.length > 0) return configDir;
  let tempDir;
  try {
    tempDir = mkdtempSync(PATH5.join(os.tmpdir(), "xy-barrel-"));
  } catch {
    return void 0;
  }
  tempDirs.push(tempDir);
  writeFileSync(PATH5.join(tempDir, "package.json"), `${JSON.stringify({ name: "xy-barrel-probe", private: true })}
`, "utf8");
  if (isVerbose) console.log(chalk5.gray(`  ${pkg} not installed \u2014 fetching it for analysis`));
  const result = spawnSync("npm", ["install", "--no-save", "--no-audit", "--no-fund", `${pkg}@latest`], {
    cwd: tempDir,
    stdio: isVerbose ? "inherit" : "ignore"
  });
  if (result.status !== 0) return void 0;
  const tempPackageDir = resolvePackageDir(pkg, tempDir);
  return tempPackageDir !== void 0 && tempPackageDir.length > 0 ? tempDir : void 0;
}
function rewriteDisallowedArray(eslintConfigPath, descriptor, imports) {
  const source = readFileSync3(eslintConfigPath, "utf8");
  const block = formatDisallowedArray(descriptor.configVarName, imports, descriptor.message);
  const pattern = new RegExp(String.raw`const ${descriptor.configVarName}\s*=\s*\[[\s\S]*?\n\]`);
  if (!pattern.test(source)) return;
  writeFileSync(eslintConfigPath, source.replace(pattern, () => block), "utf8");
}
function reportBarrelDrift(descriptor, added, removed) {
  console.log(chalk5.yellow(`
${descriptor.pkg} disallowed-imports list is out of date:`));
  for (const name of added) console.log(chalk5.green(`  + ${name} (re-exported but missing from the list)`));
  for (const name of removed) console.log(chalk5.red(`  - ${name} (in the list but no longer re-exported)`));
}
function shouldRecheckBarrels(eslintConfigPath, configDir, resolved, shouldFix, isVerbose) {
  const current = extractRestrictedPaths(resolved.get("no-restricted-imports"));
  if (current.length === 0) return false;
  const tempDirs = [];
  let isDrifted = false;
  try {
    for (const descriptor of BARREL_DESCRIPTORS) {
      const configured = current.filter((entry) => entry.message === descriptor.message).map((entry) => entry.name);
      if (configured.length === 0) continue;
      const fromDir = ensureBarrelForAnalysis(configDir, descriptor.pkg, tempDirs, isVerbose);
      if (!(fromDir != null && fromDir.length > 0)) {
        console.warn(chalk5.yellow(`Skipping ${descriptor.pkg} recheck \u2014 package could not be resolved`));
        continue;
      }
      const fresh = analyzeBarrel(descriptor.pkg, fromDir, descriptor.scopePrefix);
      if (fresh.length === 0) {
        console.warn(chalk5.yellow(`Skipping ${descriptor.pkg} recheck \u2014 no re-exported packages found`));
        continue;
      }
      const freshSet = new Set(fresh);
      const configuredSet = new Set(configured);
      const added = fresh.filter((name) => !configuredSet.has(name));
      const removed = configured.filter((name) => !freshSet.has(name));
      if (added.length === 0 && removed.length === 0) {
        if (isVerbose) console.log(chalk5.gray(`${descriptor.pkg} disallowed list is up to date (${fresh.length} packages)`));
        continue;
      }
      isDrifted = true;
      reportBarrelDrift(descriptor, added, removed);
      if (shouldFix) {
        rewriteDisallowedArray(eslintConfigPath, descriptor, fresh);
        console.log(chalk5.green(`Fixed: updated ${descriptor.configVarName} (${fresh.length} packages)`));
      }
    }
  } finally {
    for (const dir of tempDirs) rmSync(dir, { force: true, recursive: true });
  }
  return isDrifted;
}
function finalizeLintlint(eslintConfigPath, shouldFix, hasIssues) {
  if (shouldFix && hasIssues) {
    formatConfigFile(eslintConfigPath);
  }
  return !shouldFix && hasIssues && isStrictMode() ? 1 : 0;
}
async function runLintlintChecks(eslintConfigPath, configDir, source, sharedPkg, shouldFix, isVerbose) {
  const hasMismatch = shouldCheckConfigVariant(eslintConfigPath, configDir, source, sharedPkg, shouldFix, isVerbose);
  const currentSource = hasMismatch && shouldFix ? readFileSync3(eslintConfigPath, "utf8") : source;
  const sharedRules = await loadSharedRules(configDir, sharedPkg, isVerbose);
  if (sharedRules === void 0) return 1;
  const { explicit, resolved } = await loadLocalRules(eslintConfigPath, currentSource, isVerbose);
  const results = compareRules(explicit, resolved, sharedRules);
  reportResults(results, isVerbose);
  if (results.redundant.length > 0 && shouldFix) {
    fixRedundantRules(eslintConfigPath, results.redundant);
  }
  const isBarrelDrift = shouldRecheckBarrels(eslintConfigPath, configDir, resolved, shouldFix, isVerbose);
  const hasIssues = hasMismatch || results.redundant.length > 0 || isBarrelDrift;
  return finalizeLintlint(eslintConfigPath, shouldFix, hasIssues);
}
async function lintlint({ shouldFix, isVerbose } = {}) {
  const isFixEnabled = shouldFix === true;
  const isVerboseEnabled = isVerbose === true;
  const eslintConfigPath = await findUp(["eslint.config.ts", "eslint.config.mjs"]);
  if (!(eslintConfigPath != null && eslintConfigPath.length > 0)) {
    console.error(chalk5.red("No eslint.config.ts found"));
    return 1;
  }
  const configDir = PATH5.dirname(eslintConfigPath);
  if (isVerboseEnabled) {
    console.log(chalk5.gray(`Found config: ${eslintConfigPath}`));
  }
  const source = readFileSync3(eslintConfigPath, "utf8");
  const sharedPkg = detectSharedPackage(source);
  if (!(sharedPkg != null && sharedPkg.length > 0)) {
    console.log(chalk5.yellow("No @xylabs/eslint-config-flat or @xylabs/eslint-config-react-flat imports found"));
    return 0;
  }
  if (isVerboseEnabled) {
    console.log(chalk5.gray(`Shared package: ${sharedPkg}`));
  }
  return runLintlintChecks(eslintConfigPath, configDir, source, sharedPkg, isFixEnabled, isVerboseEnabled);
}
export {
  isLintInitBarrelRestriction,
  lintlint,
  shouldRecheckBarrels
};
//# sourceMappingURL=lintlint.mjs.map
