// src/xy/lint/lint/index.ts
import chalk10 from "chalk";

// src/lib/checkResult.ts
import chalk from "chalk";
function logFailure(name, result, level, suffix) {
  const message = `${name} had ${result} failures [${suffix}]`;
  if (level === "error") {
    console.error(chalk.red(message));
    return;
  }
  console.warn(chalk.yellow(message));
}
var checkResult = (name, result, level = "error", exitOnFail = false) => {
  if (!result) return;
  if (exitOnFail) {
    logFailure(name, result, level, "Exiting Process");
    process.exit(result);
    return;
  }
  logFailure(name, result, level, "Continuing");
};

// src/lib/concurrency.ts
import { AsyncLocalStorage } from "node:async_hooks";
var outputStorage = new AsyncLocalStorage();
async function runWithConcurrency(items, concurrency, fn) {
  let next = 0;
  async function worker() {
    while (next < items.length) {
      const i = next++;
      await fn(items[i]);
    }
  }
  await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => worker()));
}

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

// src/pm/resolveWorkspace.ts
import chalk2 from "chalk";
function shortName(name) {
  const slash = name.lastIndexOf("/");
  return slash === -1 ? name : name.slice(slash + 1);
}
function resolveWorkspace(workspaces, query) {
  const exact = workspaces.find((ws) => ws.name === query);
  if (exact) return exact;
  const byLocation = workspaces.find((ws) => ws.location === query);
  if (byLocation) return byLocation;
  const byShort = workspaces.filter((ws) => shortName(ws.name) === query);
  if (byShort.length === 1) return byShort[0];
  if (byShort.length > 1) {
    console.error(chalk2.red(`Ambiguous workspace "${query}"; matches: ${byShort.map((ws) => ws.name).join(", ")}`));
    return void 0;
  }
  return void 0;
}

// src/lib/packageManagerRuntime.ts
import fs from "node:fs";
import chalk3 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 askYesNo(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(chalk3.yellow(`${DISPLAY_NAMES[plan.packageManager]} is required for "${context.operation}".`));
  for (const line of plan.manualInstructions) {
    console.error(chalk3.gray(`  ${line}`));
  }
}
function installWithHomebrew(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 ensurePackageManagerInstalled(pm, context) {
  if (isPackageManagerInstalled(pm)) return true;
  const plan = getPackageManagerInstallPlan(pm, context.platform ?? currentPlatform());
  const displayName = DISPLAY_NAMES[pm];
  console.error(chalk3.yellow(`${context.operation} requires ${displayName}, but it is not installed.`));
  if (!plan.supported) {
    printManualInstructions(plan, context);
    return false;
  }
  if (!isCommandInstalled("brew")) {
    console.error(chalk3.yellow("Homebrew is not installed, so automatic installation is unavailable."));
    console.error(chalk3.gray("  Install Homebrew from https://brew.sh and then run:"));
    console.error(chalk3.gray(`  ${plan.command}`));
    return false;
  }
  const confirmed = askYesNo(chalk3.cyan(`Install ${displayName} with Homebrew now? [y/N] `));
  if (!confirmed) {
    console.error(chalk3.gray(`Skipping install. Run "${plan.command}" manually and then retry.`));
    return false;
  }
  console.error(chalk3.cyan(`Installing ${displayName} via Homebrew...
`));
  if (!installWithHomebrew(pm, context.cwd)) {
    console.error(chalk3.red(`Homebrew failed to install ${displayName}.`));
    console.error(chalk3.gray(`Run "${plan.command}" manually and then retry.`));
    return false;
  }
  if (!isPackageManagerInstalled(pm)) {
    console.error(chalk3.red(`${displayName} still does not appear to be installed after Homebrew completed.`));
    console.error(chalk3.gray(`Run "${plan.command}" manually and then retry.`));
    return false;
  }
  console.error(chalk3.green(`${displayName} installed successfully.`));
  return true;
}
function failureResult() {
  return {
    output: ["", ""],
    pid: 0,
    signal: null,
    status: 1,
    stderr: "",
    stdout: ""
  };
}
function spawnPackageManagerSync(pm, args, options) {
  if (!ensurePackageManagerInstalled(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(path5) {
  if (!existsSync(path5)) return void 0;
  try {
    return JSON.parse(readFileSync(path5, "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) 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 && 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/registry.ts
var implementations = /* @__PURE__ */ new Map();
function getPackageManager(name) {
  const pmName = name ?? detectPackageManager();
  const pm = implementations.get(pmName);
  if (!pm) {
    throw new Error(
      `No package manager implementation registered for "${pmName}". Ensure registerPackageManager() has been called before getPackageManager().`
    );
  }
  return pm;
}

// src/lib/processEx.ts
import chalk4 from "chalk";

// src/lib/withError.ts
var withError = (ex, closure, predicate = (ex2) => !!ex2.name && !!ex2.message) => {
  return predicate(ex) ? closure(ex) : void 0;
};

// src/lib/withErrnoException.ts
var withErrnoException = (ex, closure) => {
  return withError(ex, closure, (ex2) => ex2.errno !== void 0);
};

// src/lib/processEx.ts
var processEx = (ex) => {
  const error = typeof ex === "string" ? new Error(ex) : ex;
  const exitCode = withErrnoException(error, (error2) => {
    if (error2.code === "ENOENT") {
      console.error(chalk4.red(`'${error2.path}' not found.`));
    } else {
      console.error(chalk4.red(`Errno: ${error2.code}`));
    }
    return error2.errno ?? -1;
  }) ?? withError(error, (error2) => {
    console.error(chalk4.red(`${error2.name}: ${error2.message}`));
    return -1;
  }) ?? (() => {
    console.error(chalk4.red(`Unexpected Error: ${JSON.stringify(ex, null, 2)}`));
    return -1;
  })();
  process.exit(process.exitCode ?? exitCode);
};

// src/lib/safeExit.ts
function resultExitCode(result) {
  return typeof result === "number" ? result : result.exitCode;
}
var safeExit = (func, exitOnFail = true) => {
  try {
    const result = func();
    const exitCode = resultExitCode(result);
    if (exitCode && exitOnFail) {
      process.exit(exitCode);
    }
    return result;
  } catch (ex) {
    return processEx(ex);
  }
};

// src/lib/toolchainVersion.ts
import { readFileSync as readFileSync2 } from "node:fs";
import { createRequire } from "node:module";
var require2 = createRequire(import.meta.url);
function bundledToolchainVersion() {
  const pkgPath = require2.resolve("@xylabs/toolchain/package.json");
  const pkg = JSON.parse(readFileSync2(pkgPath, "utf8"));
  if (!pkg.version) throw new Error("Could not read @xylabs/toolchain version");
  return pkg.version;
}
function bundledToolchainRange() {
  return `^${bundledToolchainVersion()}`;
}

// src/lib/initCwd.ts
function INIT_CWD() {
  return process.env.INIT_CWD ?? process.cwd();
}

// src/lib/packageName.ts
import { readFileSync as readFileSync3 } from "node:fs";
import path from "node:path";
function packageName() {
  if (process.env.npm_package_name) {
    return process.env.npm_package_name;
  }
  try {
    const pkgPath = path.join(INIT_CWD(), "package.json");
    const pkg = JSON.parse(readFileSync3(pkgPath, "utf8"));
    return pkg.name;
  } catch {
    return void 0;
  }
}

// src/lib/reporting/runWithEnvelope.ts
import { performance as performance2 } from "node:perf_hooks";

// src/lib/reporting/xyReporter.ts
import { performance } from "node:perf_hooks";
var jsonMode = false;
var strictMode = false;
var originalStdoutWrite;
var envelopeEmitted = false;
var currentCommand = "unknown";
var startTime = 0;
function isJsonMode() {
  return jsonMode;
}
function isStrictMode() {
  return strictMode || process.env.XY_STRICT === "1";
}
function setCurrentCommand(name) {
  currentCommand = name;
  startTime = performance.now();
  envelopeEmitted = false;
}
function emitJson(envelope) {
  if (envelopeEmitted) return;
  envelopeEmitted = true;
  const json = JSON.stringify(envelope) + "\n";
  if (originalStdoutWrite) {
    originalStdoutWrite(json);
  } else {
    process.stdout.write(json);
  }
}

// src/lib/reporting/runWithEnvelope.ts
async function runWithEnvelope(command, action) {
  setCurrentCommand(command);
  const start = performance2.now();
  let exitCode;
  let envelope;
  try {
    const ret = await action();
    if (typeof ret === "number") {
      exitCode = ret;
    } else {
      exitCode = ret.exitCode;
      envelope = ret.envelope;
    }
  } catch (ex) {
    exitCode = 1;
    const message = ex instanceof Error ? ex.message : String(ex);
    envelope = {
      errorCount: 1,
      errors: [{ message }]
    };
    if (!isJsonMode()) {
      console.error(message);
    }
  }
  if (isJsonMode()) {
    emitJson({
      command,
      data: envelope?.data,
      durationMs: Math.round(performance2.now() - start),
      errorCount: envelope?.errorCount ?? (exitCode === 0 ? 0 : 1),
      errors: envelope?.errors,
      exitCode,
      schemaVersion: 1,
      success: exitCode === 0,
      warningCount: envelope?.warningCount ?? 0,
      warnings: envelope?.warnings
    });
  }
  return exitCode;
}
async function withEnvelope(command, action) {
  process.exitCode = await runWithEnvelope(command, action);
}

// src/lib/runInstall.ts
import chalk5 from "chalk";
function runInstall(cwd) {
  const pm = detectPackageManager();
  console.log(chalk5.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(chalk5.yellow(`${pm} install failed`));
    return false;
  }
  console.log(chalk5.green("Dependencies installed"));
  return true;
}

// src/lib/runSteps.ts
import { existsSync as existsSync3 } from "node:fs";
import chalk6 from "chalk";
var packageManagers = /* @__PURE__ */ new Set(["bun", "npm", "pnpm", "yarn"]);
var runSteps = (name, steps, exitOnFail = true, messages) => {
  return safeExit(() => {
    const pkgName = packageName();
    console.log(chalk6.green(`${name} [${pkgName}]`));
    let totalStatus = 0;
    for (const [i, [command, args, config]] of steps.entries()) {
      if (messages && Object.hasOwn(messages, i)) {
        console.log(chalk6.gray(messages[i]));
      }
      const argList = Array.isArray(args) ? args : args.split(" ");
      if (command === "node" && !existsSync3(argList[0])) {
        throw new Error(`File not found [${argList[0]}]`);
      }
      if (packageManagers.has(command) && !ensurePackageManagerInstalled(command, { operation: `${name}: ${command} ${Array.isArray(args) ? args.join(" ") : args}`.trim() })) {
        checkResult(name, 1, "error", exitOnFail);
        totalStatus += 1;
        continue;
      }
      const status = spawnSync(command, Array.isArray(args) ? args : args.split(" "), {
        ...config,
        encoding: "utf8",
        // Merge per-step env on top so callers can supply overrides
        // (e.g. NODE_OPTIONS=--max-old-space-size=...); process.env still
        // seeds the common case so FORCE_COLOR etc. survive.
        env: {
          FORCE_COLOR: "3",
          ...process.env,
          ...config?.env
        },
        stdio: isJsonMode() ? ["inherit", 2, 2] : "inherit"
      }).status ?? 0;
      checkResult(name, status, "error", exitOnFail);
      totalStatus += status ?? 0;
    }
    return totalStatus;
  }, !!exitOnFail);
};

// src/actions/dead/runtimeEntries.ts
import fs2 from "node:fs";
import path2 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(path2.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 = path2.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 = path2.join(filePath, `index${candidateExt}`);
    if (fs2.existsSync(candidate)) return candidate;
  }
  return void 0;
}
function resolveManifestEntry(location, entry) {
  if (path2.isAbsolute(entry)) return void 0;
  if (entry.includes("*")) return void 0;
  const relativeEntry = entry.startsWith(".") ? entry : `./${entry}`;
  return resolveCodeFile(path2.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) {
    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 || 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 = path2.relative(location, file);
  if (!rel.startsWith("dist" + path2.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 = [
    path2.join(location, "src", tailNoExt),
    path2.join(location, "src", tailNoExt + ".ts"),
    path2.join(location, "src", tailNoExt + ".tsx"),
    path2.join(location, "src", tailNoExt + ".mts"),
    path2.join(location, "src", tailNoExt + ".cts")
  ];
  for (const candidate of candidates) {
    const resolved = resolveCodeFile(candidate);
    if (resolved) return resolved;
  }
  return void 0;
}

// src/actions/barrel/getReExportSpecs.ts
import fs3 from "node:fs";
import PATH2 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(
    PATH2.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 as createRequire2 } from "node:module";
import PATH3 from "node:path";
var require3 = createRequire2(import.meta.url);
function findPackageRoot(entry, pkg) {
  let dir = PATH3.dirname(entry);
  for (; ; ) {
    const manifestPath = PATH3.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 = PATH3.dirname(dir);
    if (parent === dir) return void 0;
    dir = parent;
  }
}
function resolvePackageDir(pkg, fromDir) {
  try {
    return PATH3.dirname(require3.resolve(`${pkg}/package.json`, { paths: [fromDir] }));
  } catch {
  }
  try {
    const entry = require3.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) 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 || 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/incremental.ts
import { createHash } from "node:crypto";
import {
  existsSync as existsSync4,
  lstatSync,
  mkdirSync,
  readdirSync,
  readFileSync as readFileSync4,
  readlinkSync,
  writeFileSync
} from "node:fs";
import path3 from "node:path";
import * as yaml from "yaml";
var snapshotVersion = 1;
var dependencyFields = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"];
var workspaceDependencyFields = ["dependencies", "devDependencies", "peerDependencies"];
var ignoredInputDirs = /* @__PURE__ */ new Set([
  ".cache",
  ".git",
  ".next",
  ".turbo",
  "build",
  "coverage",
  "dist",
  "docs",
  "node_modules"
]);
var ignoredInputFiles = /* @__PURE__ */ new Set([".eslintcache"]);
var outputDirs = ["build", "dist"];
function toPosix(value) {
  return value.split(path3.sep).join("/");
}
function normalizeLocation(value) {
  const normalized = toPosix(value).replace(/\/$/u, "");
  return normalized === "" ? "." : normalized;
}
function stableValue(value) {
  if (Array.isArray(value)) return value.map(stableValue);
  if (value && typeof value === "object") {
    const entries = Object.entries(value).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, entryValue]) => [key, stableValue(entryValue)]);
    return Object.fromEntries(entries);
  }
  return value;
}
function hashContent(value) {
  return createHash("sha256").update(value).digest("hex");
}
function hashJson(value) {
  return hashContent(JSON.stringify(stableValue(value)));
}
function readJsonFile2(filePath) {
  try {
    return JSON.parse(readFileSync4(filePath, "utf8"));
  } catch {
    return {};
  }
}
function readPackageJson(rootDir, workspace) {
  return readJsonFile2(path3.resolve(rootDir, workspace.location, "package.json"));
}
function isStringRecord(value) {
  if (!value || typeof value !== "object") return false;
  return Object.values(value).every((entry) => typeof entry === "string");
}
function packageDeps(pkg, field) {
  const value = pkg[field];
  return isStringRecord(value) ? value : {};
}
function selectedDeps(pkg, fields) {
  const deps = {};
  for (const field of fields) {
    for (const [name, range] of Object.entries(packageDeps(pkg, field))) {
      Reflect.set(deps, `${field}:${name}`, range);
    }
  }
  return deps;
}
function workspaceDependencyNames(pkg, workspaceNames) {
  const names = /* @__PURE__ */ new Set();
  for (const field of workspaceDependencyFields) {
    for (const [name, range] of Object.entries(packageDeps(pkg, field))) {
      if (workspaceNames.has(name) && range.startsWith("workspace:")) {
        names.add(name);
      }
    }
  }
  return [...names].toSorted((a, b) => a.localeCompare(b));
}
function externalDeps(pkg, workspaceNames) {
  const deps = {};
  for (const [key, range] of Object.entries(selectedDeps(pkg, dependencyFields))) {
    const name = key.slice(key.indexOf(":") + 1);
    if (!workspaceNames.has(name) && !range.startsWith("workspace:")) {
      deps[key] = range;
    }
  }
  return deps;
}
function shouldHashRootFile(name) {
  return name === "package.json" || name === "pnpm-workspace.yaml" || name === ".npmrc" || name === ".yarnrc" || name === ".yarnrc.yml" || /^tsconfig(?:\..+)?\.json$/u.test(name) || /^(?:eslint|vite|vitest|xy|tsup)\.config\./u.test(name);
}
function rootConfigFiles(rootDir) {
  return readdirSync(rootDir, { withFileTypes: true }).filter((entry) => entry.isFile() && shouldHashRootFile(entry.name)).map((entry) => entry.name).toSorted((a, b) => a.localeCompare(b));
}
function collectFiles(dir, baseDir = dir) {
  if (!existsSync4(dir)) return [];
  const files = [];
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
    if (entry.isDirectory()) {
      if (!ignoredInputDirs.has(entry.name)) {
        files.push(...collectFiles(path3.join(dir, entry.name), baseDir));
      }
      continue;
    }
    if (!entry.isFile() && !entry.isSymbolicLink()) continue;
    if (ignoredInputFiles.has(entry.name)) continue;
    const relativePath = path3.relative(baseDir, path3.join(dir, entry.name));
    files.push(toPosix(relativePath));
  }
  return files.toSorted((a, b) => a.localeCompare(b));
}
function collectOutputFiles(workspaceDir) {
  const files = [];
  for (const outputDir of outputDirs) {
    const abs = path3.join(workspaceDir, outputDir);
    if (existsSync4(abs)) {
      files.push(...collectFiles(abs, workspaceDir).map((file) => normalizeLocation(file)));
    }
  }
  return files.toSorted((a, b) => a.localeCompare(b));
}
function hashFiles(baseDir, files) {
  const hash = createHash("sha256");
  hash.update(`count:${files.length}\0`);
  for (const file of files.toSorted((a, b) => a.localeCompare(b))) {
    const abs = path3.resolve(baseDir, file);
    hash.update(file);
    hash.update("\0");
    try {
      const stat = lstatSync(abs);
      if (stat.isSymbolicLink()) {
        hash.update("symlink");
        hash.update(readlinkSync(abs));
      } else if (stat.isFile()) {
        hash.update(readFileSync4(abs));
      }
    } catch {
      hash.update("missing");
    }
    hash.update("\0");
  }
  return hash.digest("hex");
}
function workspaceInputHash(rootDir, workspace) {
  if (workspace.location === ".") {
    return hashFiles(rootDir, rootConfigFiles(rootDir));
  }
  const workspaceDir = path3.resolve(rootDir, workspace.location);
  return hashFiles(workspaceDir, collectFiles(workspaceDir));
}
function workspaceOutputHash(rootDir, workspace) {
  const workspaceDir = path3.resolve(rootDir, workspace.location);
  return hashFiles(workspaceDir, collectOutputFiles(workspaceDir));
}
function rootHash(rootDir) {
  return hashFiles(rootDir, rootConfigFiles(rootDir));
}
function lockfileHash(rootDir, pm) {
  const lockfilePath = path3.resolve(rootDir, pm.lockfile);
  return existsSync4(lockfilePath) ? hashContent(readFileSync4(lockfilePath)) : "";
}
function readPnpmLockfileImporters(rootDir, pm) {
  if (pm.name !== "pnpm") return {};
  const lockfilePath = path3.resolve(rootDir, pm.lockfile);
  if (!existsSync4(lockfilePath)) return {};
  try {
    const parsed = yaml.parse(readFileSync4(lockfilePath, "utf8"));
    if (!parsed || typeof parsed !== "object") return {};
    const importers = parsed.importers;
    if (!importers || typeof importers !== "object" || Array.isArray(importers)) return {};
    const hashes = {};
    for (const [name, value] of Object.entries(importers).toSorted(([a], [b]) => a.localeCompare(b))) {
      hashes[normalizeLocation(name)] = hashJson(value);
    }
    return hashes;
  } catch {
    return {};
  }
}
function workspaceGraphHash(workspaceDeps) {
  return hashJson(workspaceDeps);
}
function safeToolchainVersion() {
  try {
    return bundledToolchainVersion();
  } catch {
    return "unknown";
  }
}
function createCurrentSnapshot({
  action,
  options,
  pm,
  workspaces
}) {
  const rootDir = INIT_CWD();
  const workspaceNames = new Set(workspaces.map((workspace) => workspace.name));
  const workspaceDeps = {};
  const fingerprints = {};
  for (const workspace of workspaces.toSorted((a, b) => a.name.localeCompare(b.name))) {
    const pkg = readPackageJson(rootDir, workspace);
    const packageJsonPath = path3.resolve(rootDir, workspace.location, "package.json");
    const deps = workspaceDependencyNames(pkg, workspaceNames);
    workspaceDeps[workspace.name] = deps;
    fingerprints[workspace.name] = {
      externalDepsHash: hashJson(externalDeps(pkg, workspaceNames)),
      inputHash: workspaceInputHash(rootDir, workspace),
      location: normalizeLocation(workspace.location),
      name: workspace.name,
      outputHash: workspaceOutputHash(rootDir, workspace),
      packageJsonHash: existsSync4(packageJsonPath) ? hashContent(readFileSync4(packageJsonPath)) : "",
      workspaceDepsHash: hashJson(deps)
    };
  }
  return {
    action,
    lockfileHash: lockfileHash(rootDir, pm),
    lockfileImporters: readPnpmLockfileImporters(rootDir, pm),
    optionsHash: options === void 0 ? void 0 : hashJson(options),
    packageManager: pm.name,
    rootHash: rootHash(rootDir),
    toolchainVersion: safeToolchainVersion(),
    version: snapshotVersion,
    workspaceGraphHash: workspaceGraphHash(workspaceDeps),
    workspaces: fingerprints
  };
}
function snapshotPath(rootDir, action) {
  return path3.resolve(rootDir, ".xy/cache/incremental", `${action}.json`);
}
function readSnapshot(action) {
  const filePath = snapshotPath(INIT_CWD(), action);
  if (!existsSync4(filePath)) return void 0;
  try {
    const parsed = JSON.parse(readFileSync4(filePath, "utf8"));
    return parsed.version === snapshotVersion && parsed.action === action ? parsed : void 0;
  } catch {
    return void 0;
  }
}
function workspaceNamesChanged(previous, current) {
  const previousEntries = Object.values(previous.workspaces).map((workspace) => `${workspace.name}\0${workspace.location}`).toSorted((a, b) => a.localeCompare(b));
  const currentEntries = Object.values(current.workspaces).map((workspace) => `${workspace.name}\0${workspace.location}`).toSorted((a, b) => a.localeCompare(b));
  return previousEntries.join("\n") !== currentEntries.join("\n");
}
function createDependentsMap(workspaces) {
  const rootDir = INIT_CWD();
  const workspaceNames = new Set(workspaces.map((workspace) => workspace.name));
  const dependents = /* @__PURE__ */ new Map();
  for (const workspace of workspaces) {
    dependents.set(workspace.name, /* @__PURE__ */ new Set());
  }
  for (const workspace of workspaces) {
    const deps = workspaceDependencyNames(readPackageJson(rootDir, workspace), workspaceNames);
    for (const dep of deps) {
      dependents.get(dep)?.add(workspace.name);
    }
  }
  return dependents;
}
function expandWithDependents(workspaceNames, workspaces) {
  const dependents = createDependentsMap(workspaces);
  const queue = [...workspaceNames];
  for (const name of queue) {
    for (const dependent of dependents.get(name) ?? []) {
      if (!workspaceNames.has(dependent)) {
        workspaceNames.add(dependent);
        queue.push(dependent);
      }
    }
  }
  return [...workspaceNames].toSorted((a, b) => a.localeCompare(b));
}
function resolvePnpmLockfileImpact(previous, current, workspaces) {
  const byLocation = new Map(workspaces.map((workspace) => [normalizeLocation(workspace.location), workspace.name]));
  const allImporters = /* @__PURE__ */ new Set([
    ...Object.keys(previous.lockfileImporters),
    ...Object.keys(current.lockfileImporters)
  ]);
  const changedImporters = [...allImporters].filter((importer) => previous.lockfileImporters[importer] !== current.lockfileImporters[importer]).toSorted((a, b) => a.localeCompare(b));
  if (changedImporters.length === 0) {
    return { full: "lockfile changed outside workspace importers", workspaceNames: [] };
  }
  const affected = /* @__PURE__ */ new Set();
  for (const importer of changedImporters) {
    if (importer === ".") {
      return { full: "root lockfile importer changed", workspaceNames: [] };
    }
    const workspaceName = byLocation.get(importer);
    if (!workspaceName) {
      return { full: `lockfile importer changed for unknown workspace: ${importer}`, workspaceNames: [] };
    }
    affected.add(workspaceName);
  }
  return { workspaceNames: [...affected].toSorted((a, b) => a.localeCompare(b)) };
}
function resolveLockfileImpact(previous, current, workspaces) {
  if (previous.lockfileHash === current.lockfileHash) return { workspaceNames: [] };
  if (current.packageManager !== "pnpm") {
    return { full: `${current.packageManager} lockfile changed`, workspaceNames: [] };
  }
  return resolvePnpmLockfileImpact(previous, current, workspaces);
}
function fullPlan(action, current, previous, reason) {
  return {
    action,
    affectedWorkspaceNames: Object.keys(current.workspaces).toSorted((a, b) => a.localeCompare(b)),
    current,
    full: true,
    previous,
    reason
  };
}
function compatibilityReason(previous, current) {
  if (previous.version !== snapshotVersion) return "snapshot version changed";
  if (previous.packageManager !== current.packageManager) return "package manager changed";
  if (previous.toolchainVersion !== current.toolchainVersion) return "toolchain version changed";
  if (previous.optionsHash !== current.optionsHash) return `${current.action} options changed`;
  if (workspaceNamesChanged(previous, current)) return "workspace set changed";
  if (previous.rootHash !== current.rootHash) return "root configuration changed";
  return void 0;
}
function tracksOutputs(action) {
  return action !== "lint";
}
function expandsDependents(action) {
  return action !== "lint";
}
function workspaceChanged(action, previous, current) {
  return previous.inputHash !== current.inputHash || tracksOutputs(action) && previous.outputHash !== current.outputHash || previous.packageJsonHash !== current.packageJsonHash || previous.workspaceDepsHash !== current.workspaceDepsHash || previous.externalDepsHash !== current.externalDepsHash;
}
function collectChangedWorkspaceNames(action, previous, current) {
  const affected = /* @__PURE__ */ new Set();
  for (const [name, workspace] of Object.entries(current.workspaces)) {
    const prior = previous.workspaces[name];
    if (!prior) return { affected, fullReason: `workspace added: ${name}` };
    if (workspaceChanged(action, prior, workspace)) affected.add(name);
  }
  if (previous.workspaceGraphHash !== current.workspaceGraphHash) {
    for (const [name, workspace] of Object.entries(current.workspaces)) {
      if (previous.workspaces[name]?.workspaceDepsHash !== workspace.workspaceDepsHash) affected.add(name);
    }
  }
  return { affected };
}
function createIncrementalPlan(params) {
  const current = createCurrentSnapshot(params);
  const previous = readSnapshot(params.action);
  const {
    action,
    verbose,
    workspaces
  } = params;
  if (!previous) return fullPlan(action, current, previous, "no previous snapshot");
  const incompatible = compatibilityReason(previous, current);
  if (incompatible) return fullPlan(action, current, previous, incompatible);
  const { affected, fullReason } = collectChangedWorkspaceNames(action, previous, current);
  if (fullReason) return fullPlan(action, current, previous, fullReason);
  const lockImpact = resolveLockfileImpact(previous, current, workspaces);
  if (lockImpact.full) return fullPlan(action, current, previous, lockImpact.full);
  for (const workspaceName of lockImpact.workspaceNames) {
    affected.add(workspaceName);
  }
  const affectedWorkspaceNames = expandsDependents(action) ? expandWithDependents(affected, workspaces) : [...affected].toSorted((a, b) => a.localeCompare(b));
  if (verbose && affectedWorkspaceNames.length > 0) {
    console.log(`Incremental ${action}: ${affectedWorkspaceNames.join(", ")}`);
  }
  return {
    action,
    affectedWorkspaceNames,
    current,
    full: false,
    previous
  };
}
function writeIncrementalSnapshot(params) {
  const rootDir = INIT_CWD();
  const filePath = snapshotPath(rootDir, params.action);
  mkdirSync(path3.dirname(filePath), { recursive: true });
  writeFileSync(filePath, `${JSON.stringify(createCurrentSnapshot(params), null, 2)}
`);
}

// src/actions/result.ts
function actionResult({
  errorCount,
  exitCode = errorCount,
  warningCount
}) {
  if (errorCount === 0 && warningCount === 0 && exitCode === 0) return 0;
  return {
    envelope: {
      errorCount,
      warningCount
    },
    exitCode
  };
}
function resultFromExitCode(exitCode) {
  return actionResult({
    errorCount: exitCode === 0 ? 0 : Math.max(1, exitCode),
    exitCode,
    warningCount: 0
  });
}
function resultExitCode2(result) {
  return typeof result === "number" ? result : result.exitCode;
}
function resultErrorCount(result) {
  if (typeof result === "number") return result === 0 ? 0 : Math.max(1, result);
  return result.envelope?.errorCount ?? (result.exitCode === 0 ? 0 : Math.max(1, result.exitCode));
}
function resultWarningCount(result) {
  return typeof result === "number" ? 0 : result.envelope?.warningCount ?? 0;
}
function isCleanResult(result) {
  return resultExitCode2(result) === 0 && resultErrorCount(result) === 0 && resultWarningCount(result) === 0;
}

// src/actions/lint.ts
import chalk8 from "chalk";

// src/actions/lintNext.ts
import { createRequire as createRequire3 } from "node:module";
import path4 from "node:path";
import { pathToFileURL } from "node:url";
import chalk7 from "chalk";
var lintNextIgnorePatterns = ["packages/**"];
var lintNextResultMarker = "__XY_LINT_NEXT_RESULT__";
var require4 = createRequire3(import.meta.url);
var chalkImportUrl = pathToFileURL(require4.resolve("chalk")).href;
var cycleRuleFilePatterns = [
  "**/*.ts",
  "**/*.tsx",
  "**/*.mts",
  "**/*.cts",
  "**/*.js",
  "**/*.jsx",
  "**/*.cjs",
  "**/*.mjs",
  "**/*.d.ts",
  "**/*.d.tsx",
  "**/*.d.jsx",
  "**/*.d.mts",
  "**/*.d.cts"
];
var lintNextWorkerSource = String.raw`
import path from 'node:path'
import { ESLint } from 'eslint'

const marker = ${JSON.stringify(lintNextResultMarker)}
const options = JSON.parse(process.env.XY_LINT_NEXT_OPTIONS ?? '{}')
const cycleRuleFilePatterns = ${JSON.stringify(cycleRuleFilePatterns)}
const { default: chalk } = await import(process.env.XY_LINT_NEXT_CHALK_URL)
const colors = ['white', 'yellow', 'red']
const severity = ['none', 'warning', 'error']

function dumpMessages(lintResults) {
  for (const lintResult of lintResults) {
    if (lintResult.messages.length === 0) continue
    console.log(chalk.gray('\n' + lintResult.filePath))
    for (const message of lintResult.messages) {
      console.log(
        chalk.gray('\t' + message.line + ':' + message.column),
        chalk[colors[message.severity]]('\t' + severity[message.severity]),
        chalk.white('\t' + message.message),
        chalk.gray('\t' + message.ruleId),
      )
    }
  }
}

try {
  const cwd = process.cwd()
  const cycleOverrideConfig = options.cycleDepth === undefined
    ? undefined
    : {
        files: cycleRuleFilePatterns,
        rules: { 'import-x/no-cycle': ['warn', { maxDepth: options.cycleDepth }] },
      }
  const engine = new ESLint({
    cache: options.cache,
    cacheLocation: path.join(cwd, '.eslintcache'),
    cacheStrategy: 'content',
    cwd,
    fix: options.fix,
    ignorePatterns: options.ignorePatterns,
    overrideConfig: cycleOverrideConfig,
    warnIgnored: false,
  })

  const lintResults = await engine.lintFiles('.')
  dumpMessages(lintResults)

  if (options.fix) {
    await ESLint.outputFixes(lintResults)
  }

  const errors = lintResults.reduce((sum, r) => sum + r.errorCount, 0)
  const warnings = lintResults.reduce((sum, r) => sum + r.warningCount, 0)
  const files = lintResults.length

  if (options.verbose) {
    const filesColor = files < 100 ? 'green' : files < 1000 ? 'yellow' : 'red'
    console.log(chalk.white('  ' + chalk[filesColor](files) + ' files linted'))
  }

  console.log(marker + JSON.stringify({ errors, files, warnings }))
} catch (ex) {
  console.error(ex instanceof Error ? (ex.stack ?? ex.message) : String(ex))
  console.log(marker + JSON.stringify({ errors: 1, files: 0, warnings: 0 }))
  process.exitCode = 1
}
`;
function formatDuration(ms) {
  if (ms < 1e3) return `${ms}ms`;
  return `${(ms / 1e3).toFixed(2)}s`;
}
function resultColor(result) {
  if (result.errors > 0) return "red";
  if (result.warnings > 0) return "yellow";
  return "green";
}
function parseLintNextOutput(output, status) {
  const markerIndex = output.lastIndexOf(lintNextResultMarker);
  if (markerIndex === -1) {
    return {
      errors: status === 0 ? 0 : 1,
      files: 0,
      output,
      warnings: 0
    };
  }
  const beforeMarker = output.slice(0, markerIndex);
  const afterMarker = output.slice(markerIndex + lintNextResultMarker.length);
  const [jsonLine = "", ...remainingLines] = afterMarker.split(/\r?\n/);
  try {
    const parsed = JSON.parse(jsonLine);
    return {
      errors: parsed.errors,
      files: parsed.files,
      output: beforeMarker + remainingLines.join("\n"),
      warnings: parsed.warnings
    };
  } catch {
    return {
      errors: status === 0 ? 0 : 1,
      files: 0,
      output,
      warnings: 0
    };
  }
}
async function lintOnePackageProcess({
  cache,
  cwd,
  cycleDepth,
  fix,
  verbose
}) {
  return await new Promise((resolve) => {
    const output = [];
    const env = {
      ...process.env,
      FORCE_COLOR: "3",
      XY_LINT_NEXT_OPTIONS: JSON.stringify({
        cache,
        cycleDepth,
        fix,
        ignorePatterns: lintNextIgnorePatterns,
        verbose
      }),
      XY_LINT_NEXT_CHALK_URL: chalkImportUrl
    };
    delete env.NO_COLOR;
    delete env.NODE_DISABLE_COLORS;
    const child = spawn(process.execPath, ["--input-type=module", "--eval", lintNextWorkerSource], {
      cwd,
      env,
      stdio: ["ignore", "pipe", "pipe"]
    });
    child.stdout?.on("data", (chunk) => {
      output.push(String(chunk));
    });
    child.stderr?.on("data", (chunk) => {
      output.push(String(chunk));
    });
    child.on("error", (ex) => {
      resolve({
        errors: 1,
        files: 0,
        output: `${ex.message}
`,
        warnings: 0
      });
    });
    child.on("close", (status) => {
      resolve(parseLintNextOutput(output.join(""), status));
    });
  });
}
function printPackageResult(label, result) {
  const color = resultColor(result);
  console.log(
    chalk7[color](`${label} [${result.pkg}]`) + chalk7.gray(` (${result.files} files, ${formatDuration(result.timeMs)})`)
  );
  if (result.output.length > 0) {
    process.stdout.write(result.output.endsWith("\n") ? result.output : `${result.output}
`);
  }
}
async function lintNext({
  cache = false,
  cycleDepth,
  fix = false,
  jobs,
  pkg,
  verbose = false,
  workspaces: targetWorkspaces
}) {
  const rootDir = INIT_CWD();
  const pm = getPackageManager();
  const allWorkspaces = pm.listWorkspaces();
  let workspaces = targetWorkspaces ?? allWorkspaces;
  if (pkg !== void 0) {
    const targetWorkspace = resolveWorkspace(allWorkspaces, pkg);
    workspaces = targetWorkspace === void 0 ? [] : [targetWorkspace];
  }
  if (pkg === void 0 && targetWorkspaces !== void 0 && workspaces.length === 0) {
    console.log(chalk7.gray("No workspaces to lint"));
    return 0;
  }
  if (workspaces.length === 0) {
    console.log(chalk7.red(pkg ? `Package "${pkg}" not found` : "No workspaces found"));
    return resultFromExitCode(1);
  }
  const concurrency = jobs;
  const label = fix ? "Fix" : cycleDepth === void 0 ? "Lint" : "Cycle";
  const results = Array.from(
    { length: workspaces.length },
    () => ({
      errors: 0,
      files: 0,
      output: "",
      pkg: "",
      timeMs: 0,
      warnings: 0
    })
  );
  await runWithConcurrency(
    workspaces.map((ws, i) => ({ i, ws })),
    concurrency,
    async ({ i, ws }) => {
      const pkgStart = Date.now();
      const absCwd = path4.resolve(rootDir, ws.location);
      const {
        errors,
        files,
        output,
        warnings
      } = await lintOnePackageProcess({
        cache,
        cwd: absCwd,
        cycleDepth,
        fix,
        verbose
      });
      const result = {
        errors,
        files,
        output,
        pkg: ws.name,
        timeMs: Date.now() - pkgStart,
        warnings
      };
      results[i] = result;
      printPackageResult(label, result);
    }
  );
  let totalErrors = 0;
  let totalWarnings = 0;
  let totalFiles = 0;
  for (const result of results) {
    totalErrors += result.errors;
    totalWarnings += result.warnings;
    totalFiles += result.files;
  }
  const errColor = totalErrors > 0 ? "red" : "green";
  const warnColor = totalWarnings > 0 ? "yellow" : "green";
  console.log(
    chalk7[errColor](`${totalErrors} errors`) + chalk7.gray(", ") + chalk7[warnColor](`${totalWarnings} warnings`) + chalk7.gray(` across ${totalFiles} files in ${workspaces.length} packages`)
  );
  return actionResult({
    errorCount: totalErrors,
    exitCode: totalErrors + (isStrictMode() ? totalWarnings : 0),
    warningCount: totalWarnings
  });
}

// src/actions/lint.ts
function selectedWorkspaces(workspaces, names) {
  const selected = new Set(names);
  return workspaces.filter((workspace) => selected.has(workspace.name));
}
function shouldUseIncremental(incremental) {
  return incremental === true;
}
function lintOptionsHash({
  cache,
  cycleDepth,
  fix
}) {
  return {
    cache: cache ?? false,
    cycleDepth,
    fix: fix ?? false,
    strict: isStrictMode()
  };
}
var lintPackage = ({
  pkg,
  fix,
  verbose
}) => {
  const pm = getPackageManager();
  return runSteps(`${fix ? "Fix" : "Lint"} [${pkg}]`, [
    pm.runInWorkspace(pkg, fix ? "package-fix" : verbose ? "package-lint-verbose" : "package-lint")
  ]);
};
async function lintIncremental({
  cache,
  cycleDepth,
  fix,
  jobs,
  verbose,
  workspaces: targetWorkspaces
}) {
  const pm = getPackageManager();
  const allWorkspaces = targetWorkspaces ?? pm.listWorkspaces();
  if (allWorkspaces.length === 0) {
    return await lintNext({
      cache,
      cycleDepth,
      fix,
      jobs,
      verbose
    });
  }
  const plan = createIncrementalPlan({
    action: "lint",
    options: lintOptionsHash({
      cache,
      cycleDepth,
      fix
    }),
    pm,
    verbose,
    workspaces: allWorkspaces
  });
  if (plan.full && plan.reason) {
    console.log(chalk8.gray(`  Full lint: ${plan.reason}`));
  }
  if (!plan.full && plan.affectedWorkspaceNames.length === 0) {
    console.log(chalk8.gray("  No changed packages to lint."));
    writeIncrementalSnapshot({
      action: "lint",
      options: lintOptionsHash({
        cache,
        cycleDepth,
        fix
      }),
      pm,
      workspaces: allWorkspaces
    });
    return 0;
  }
  const workspaces = plan.full ? allWorkspaces : selectedWorkspaces(allWorkspaces, plan.affectedWorkspaceNames);
  const result = await lintNext({
    cache,
    cycleDepth,
    fix,
    jobs,
    verbose,
    workspaces
  });
  if (isCleanResult(result)) {
    writeIncrementalSnapshot({
      action: "lint",
      options: lintOptionsHash({
        cache,
        cycleDepth,
        fix
      }),
      pm,
      workspaces: allWorkspaces
    });
  }
  return result;
}
var lint = ({
  cache,
  cycleDepth,
  fix,
  incremental,
  jobs,
  prev,
  pkg,
  verbose,
  workspaces
}) => {
  if (!prev) {
    if (pkg === void 0 && shouldUseIncremental(incremental)) {
      return lintIncremental({
        cache,
        cycleDepth,
        fix,
        jobs,
        verbose,
        workspaces
      });
    }
    const params = {
      cache,
      fix,
      jobs,
      pkg,
      verbose,
      workspaces
    };
    if (cycleDepth !== void 0) params.cycleDepth = cycleDepth;
    return lintNext(params);
  }
  return pkg === void 0 ? lintAllPackages({ fix }) : lintPackage({
    pkg,
    fix,
    verbose
  });
};
var lintAllPackages = ({ fix = false } = {}) => {
  const fixOptions = fix ? ["--fix"] : [];
  const strictOptions = isStrictMode() ? ["--max-warnings", "0"] : [];
  return runSteps(`${fix ? "Fix" : "Lint"} [All-Packages]`, [
    ["eslint", ["--cache", "--cache-location", ".eslintcache", "--cache-strategy", "content", ...fixOptions, ...strictOptions]]
  ]);
};

// src/actions/lint-init.ts
import {
  existsSync as existsSync5,
  readFileSync as readFileSync5,
  unlinkSync,
  writeFileSync as writeFileSync2
} from "node:fs";
import PATH4 from "node:path";
import { createInterface } from "node:readline";
import chalk9 from "chalk";
import { globSync as globSync2 } from "glob";
function askConfirmation(question) {
  const rl = createInterface({ input: process.stdin, output: process.stdout });
  return new Promise((resolve) => {
    rl.question(question, (answer) => {
      rl.close();
      resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
    });
  });
}
var XYLABS_SDK_IMPORT_MESSAGE = "Use '@xylabs/sdk-js' instead.";
var XYO_SDK_IMPORT_MESSAGE = "Use '@xyo-network/sdk-js' instead.";
var BARREL_DESCRIPTORS = [
  {
    configVarName: "disallowedImportsXyLabs",
    message: XYLABS_SDK_IMPORT_MESSAGE,
    pkg: "@xylabs/sdk-js",
    scopePrefix: "@xylabs/"
  },
  {
    configVarName: "disallowedImportsXyo",
    message: XYO_SDK_IMPORT_MESSAGE,
    pkg: "@xyo-network/sdk-js",
    scopePrefix: "@xyo-network/"
  }
];
function getRequiredDevDependencies(react) {
  const configPkg = react ? "@xylabs/eslint-config-react-flat" : "@xylabs/eslint-config-flat";
  return {
    [configPkg]: bundledToolchainRange(),
    eslint: "^10.0.0"
  };
}
function formatDisallowedArray(name, imports, message) {
  const items = imports.map((i) => `  { name: '${i}', message: "${message}" },`).join("\n");
  return `const ${name} = [
${items}
]`;
}
function generateEslintConfig({ barrels, react }) {
  const configPkg = react ? "@xylabs/eslint-config-react-flat" : "@xylabs/eslint-config-flat";
  const lines = [
    "import type { Linter } from 'eslint'",
    "",
    `import { config as xylabsConfig } from '${configPkg}'`,
    ""
  ];
  for (const barrel of barrels) {
    lines.push(formatDisallowedArray(barrel.configVarName, barrel.imports, barrel.message), "");
  }
  lines.push("const config: Linter.Config[] = [", "  { ignores: ['.yarn/**', 'build', '**/build/**', '**/dist/**', 'dist', 'node_modules/**', '**/node_modules/**', '**/*.md', '.claude/worktrees/*'] },", "  ...xylabsConfig,");
  if (barrels.length > 0) {
    lines.push("  {", "    rules:", "    {", "      'no-restricted-imports': [", "        'warn',", "        {", "          paths: [");
    for (const barrel of barrels) {
      lines.push(`            ...${barrel.configVarName},`);
    }
    lines.push("          ],", "        },", "      ],", "    },", "  },");
  }
  lines.push("]", "", "export default config", "");
  return lines.join("\n");
}
function addDevDependencies(packageJsonPath, requiredDeps, verbose) {
  const content = readFileSync5(packageJsonPath, "utf8");
  const pkg = JSON.parse(content);
  const devDeps = pkg.devDependencies ?? {};
  let changed = false;
  for (const [name, version] of Object.entries(requiredDeps)) {
    if (!Object.hasOwn(devDeps, name)) {
      devDeps[name] = version;
      changed = true;
      if (verbose) console.log(chalk9.gray(`  Added ${name}@${version} to devDependencies`));
    } else if (verbose) {
      console.log(chalk9.gray(`  ${name} already in devDependencies`));
    }
  }
  if (changed) {
    const sorted = Object.fromEntries(Object.entries(devDeps).toSorted(([a], [b]) => a.localeCompare(b)));
    pkg.devDependencies = sorted;
    writeFileSync2(packageJsonPath, `${JSON.stringify(pkg, null, 2)}
`, "utf8");
    console.log(chalk9.green("Updated package.json devDependencies"));
  } else {
    console.log(chalk9.gray("package.json devDependencies already up to date"));
  }
  return changed;
}
function hasReactDependency(packageJsonPath) {
  try {
    const content = readFileSync5(packageJsonPath, "utf8");
    const pkg = JSON.parse(content);
    const deps = pkg.dependencies;
    const devDeps = pkg.devDependencies;
    const peerDeps = pkg.peerDependencies;
    return deps?.react != null || devDeps?.react != null || peerDeps?.react != null;
  } catch {
    return false;
  }
}
function detectReactInMonorepo(cwd, verbose) {
  const rootPkgPath = PATH4.resolve(cwd, "package.json");
  if (hasReactDependency(rootPkgPath)) {
    if (verbose) console.log(chalk9.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 = PATH4.resolve(cwd, relPath);
    if (hasReactDependency(fullPath)) {
      if (verbose) console.log(chalk9.gray(`  React detected in ${relPath}`));
      return true;
    }
  }
  return false;
}
function findExistingConfig(configPath, legacyConfigPath) {
  if (existsSync5(configPath)) return configPath;
  if (existsSync5(legacyConfigPath)) return legacyConfigPath;
  return void 0;
}
function removeLegacyConfig(legacyConfigPath) {
  if (!existsSync5(legacyConfigPath)) {
    return;
  }
  unlinkSync(legacyConfigPath);
  console.log(chalk9.gray("Removed legacy eslint.config.mjs"));
}
function updateDependencies(packageJsonPath, react, cwd, verbose) {
  if (!existsSync5(packageJsonPath)) {
    console.log(chalk9.yellow("No package.json found \u2014 skipping dependency updates"));
    return;
  }
  const changed = addDevDependencies(packageJsonPath, getRequiredDevDependencies(react), verbose);
  if (changed) {
    runInstall(cwd);
  }
}
function ensureBarrelInstalled(cwd, barrelPkg, verbose) {
  const existing = resolvePackageDir(barrelPkg, cwd);
  if (existing) return existing;
  const packageJsonPath = PATH4.resolve(cwd, "package.json");
  if (!existsSync5(packageJsonPath)) {
    console.warn(chalk9.yellow(`No package.json found \u2014 cannot install ${barrelPkg} for barrel analysis`));
    return void 0;
  }
  console.log(chalk9.cyan(`${barrelPkg} not installed \u2014 adding it so its barrel can be analyzed`));
  addDevDependencies(packageJsonPath, { [barrelPkg]: "latest" }, verbose);
  runInstall(cwd);
  return resolvePackageDir(barrelPkg, cwd);
}
function resolveEnabledBarrels(cwd, enabled, verbose) {
  const resolved = [];
  for (const descriptor of enabled) {
    const location = ensureBarrelInstalled(cwd, descriptor.pkg, verbose);
    if (!location) {
      console.warn(chalk9.yellow(`Skipping ${descriptor.pkg} import restrictions \u2014 package could not be resolved`));
      continue;
    }
    const imports = analyzeBarrel(descriptor.pkg, cwd, descriptor.scopePrefix);
    if (imports.length === 0) {
      console.warn(chalk9.yellow(`Skipping ${descriptor.pkg} import restrictions \u2014 no re-exported packages found`));
      continue;
    }
    if (verbose) console.log(chalk9.gray(`  ${descriptor.pkg}: ${imports.length} re-exported package(s)`));
    resolved.push({
      configVarName: descriptor.configVarName,
      imports,
      message: descriptor.message
    });
  }
  return resolved;
}
async function lintInit({ verbose } = {}) {
  const cwd = INIT_CWD();
  const configPath = PATH4.resolve(cwd, "eslint.config.ts");
  const legacyConfigPath = PATH4.resolve(cwd, "eslint.config.mjs");
  const existingPath = findExistingConfig(configPath, legacyConfigPath);
  if (existingPath) {
    const filename = PATH4.basename(existingPath);
    const confirmed = await askConfirmation(
      chalk9.yellow(`${filename} already exists. Replace it with eslint.config.ts? (y/N) `)
    );
    if (!confirmed) {
      console.log(chalk9.gray(`Skipped \u2014 existing ${filename} preserved`));
      return 0;
    }
  }
  const react = detectReactInMonorepo(cwd, verbose);
  if (react) {
    console.log(chalk9.cyan("Detected React packages \u2014 using @xylabs/eslint-config-react-flat"));
  } else if (verbose) {
    console.log(chalk9.gray("  No React packages detected \u2014 using @xylabs/eslint-config-flat"));
  }
  const enabledBarrels = [];
  for (const descriptor of BARREL_DESCRIPTORS) {
    const confirmed = await askConfirmation(
      chalk9.cyan(`Disallow ${descriptor.pkg} barrel imports? (y/N) `)
    );
    if (confirmed) enabledBarrels.push(descriptor);
  }
  const barrels = resolveEnabledBarrels(cwd, enabledBarrels, verbose);
  const config = generateEslintConfig({ barrels, react });
  writeFileSync2(configPath, config, "utf8");
  console.log(chalk9.green("Generated eslint.config.ts"));
  removeLegacyConfig(legacyConfigPath);
  updateDependencies(PATH4.resolve(cwd, "package.json"), react, cwd, verbose);
  return 0;
}

// src/xy/lint/lint/initCommand.ts
var initCommand = {
  command: "init",
  describe: "Generate eslint.config.ts and add ESLint dependencies",
  handler: async (argv) => {
    if (argv.verbose) console.log("Lint Init");
    await withEnvelope("lint init", () => lintInit({ verbose: !!argv.verbose }));
  }
};

// src/xy/param.ts
var packagePositionalParam = (yargs) => {
  return yargs.positional("package", { describe: "Specific package to target", type: "string" });
};

// src/xy/lint/lint/runCommand.ts
var runCommand = {
  aliases: ["$0"],
  builder: (yargs) => {
    return packagePositionalParam(yargs).option("fix", {
      alias: "f",
      default: false,
      description: "Fix fixable issues",
      type: "boolean"
    }).option("cache", {
      alias: "c",
      default: false,
      description: "Use caching for performance",
      type: "boolean"
    }).option("next", {
      default: false,
      description: "Deprecated: per-package lint is the default",
      hidden: true,
      type: "boolean"
    }).option("prev", {
      default: false,
      description: "Use the previous all-packages lint runner",
      type: "boolean"
    });
  },
  command: "run [package]",
  describe: "Run ESLint",
  handler: async (argv) => {
    if (argv.verbose) console.log("Lint");
    await withEnvelope("lint", () => lint({
      cache: argv.cache,
      fix: argv.fix,
      incremental: argv.incremental,
      jobs: argv.jobs,
      prev: argv.prev,
      pkg: argv.package,
      verbose: !!argv.verbose
    }));
  }
};

// src/xy/lint/lint/index.ts
var lintCommand = {
  builder: (yargs) => {
    return yargs.command(runCommand).command(initCommand).option("init", {
      default: false,
      description: "Generate eslint.config.ts and add ESLint dependencies",
      hidden: true,
      type: "boolean"
    });
  },
  command: "lint",
  describe: "Lint - Run ESLint",
  handler: async (argv) => {
    if (!argv.init) {
      return;
    }
    console.warn(chalk10.yellow('Deprecated: use "xy lint init" instead of "xy lint --init"'));
    await withEnvelope("lint init", () => lintInit({ verbose: !!argv.verbose }));
  }
};
export {
  lintCommand
};
//# sourceMappingURL=index.mjs.map
