// 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", shouldExitOnFail = false) => {
  if (!result) return;
  if (shouldExitOnFail) {
    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 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(chalk3.yellow(`${DISPLAY_NAMES[plan.packageManager]} is required for "${context.operation}".`));
  for (const line of plan.manualInstructions) {
    console.error(chalk3.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(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 isConfirmed = shouldAskYesNo(chalk3.cyan(`Install ${displayName} with Homebrew now? [y/N] `));
  if (!isConfirmed) {
    console.error(chalk3.gray(`Skipping install. Run "${plan.command}" manually and then retry.`));
    return false;
  }
  console.error(chalk3.cyan(`Installing ${displayName} via Homebrew...
`));
  if (!shouldInstallWithHomebrew(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;
}

// src/pm/workspaces.ts
import { existsSync, readFileSync } from "node:fs";
import PATH from "node:path";
import { globSync } from "glob";
function readJsonFile(path6) {
  if (!existsSync(path6)) return void 0;
  try {
    return JSON.parse(readFileSync(path6, "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/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, shouldExitOnFail = true) => {
  try {
    const result = func();
    const exitCode = resultExitCode(result);
    if (exitCode && shouldExitOnFail) {
      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 != null && pkg.version.length > 0)) throw new Error("Could not read @xylabs/toolchain version");
  return pkg.version;
}

// src/lib/eslintCache.ts
import { mkdirSync } from "node:fs";
import path from "node:path";
function workspaceEslintCachePath(rootDir, workspaceLocation) {
  const segment = workspaceLocation === "." ? "root" : workspaceLocation;
  return path.resolve(rootDir, ".xy/cache/eslint", segment, ".eslintcache");
}
function ensureEslintCacheDir(cachePath) {
  mkdirSync(path.dirname(cachePath), { recursive: true });
}

// 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 path2 from "node:path";
function packageName() {
  if (process.env.npm_package_name != null && process.env.npm_package_name.length > 0) {
    return process.env.npm_package_name;
  }
  try {
    const pkgPath = path2.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 reporterState = {
  currentCommand: "unknown",
  isEnvelopeEmitted: false,
  isJsonModeEnabled: false,
  isStrictModeEnabled: false,
  originalStdoutWrite: void 0,
  startTime: 0
};
function isJsonMode() {
  return reporterState.isJsonModeEnabled;
}
function isStrictMode() {
  return reporterState.isStrictModeEnabled || process.env.XY_STRICT === "1";
}
function setCurrentCommand(name) {
  reporterState.currentCommand = name;
  reporterState.startTime = performance.now();
  reporterState.isEnvelopeEmitted = false;
}
function emitJson(envelope) {
  if (reporterState.isEnvelopeEmitted) return;
  reporterState.isEnvelopeEmitted = true;
  const json = JSON.stringify(envelope) + "\n";
  if (reporterState.originalStdoutWrite) {
    reporterState.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/runSteps.ts
import { existsSync as existsSync3 } from "node:fs";
import chalk5 from "chalk";
var packageManagers = /* @__PURE__ */ new Set(["bun", "npm", "pnpm", "yarn"]);
var runSteps = (name, steps, shouldExitOnFail = true, messages) => {
  return safeExit(() => {
    const pkgName = packageName();
    console.log(chalk5.green(`${name} [${pkgName}]`));
    let totalStatus = 0;
    for (const [i, [command, args, config]] of steps.entries()) {
      if (messages && Object.hasOwn(messages, i)) {
        console.log(chalk5.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) && !didEnsurePackageManagerInstalled(command, { operation: `${name}: ${command} ${Array.isArray(args) ? args.join(" ") : args}`.trim() })) {
        checkResult(name, 1, "error", shouldExitOnFail);
        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", shouldExitOnFail);
      totalStatus += status ?? 0;
    }
    return totalStatus;
  }, !!shouldExitOnFail);
};

// src/actions/incremental.ts
import { createHash } from "node:crypto";
import {
  existsSync as existsSync4,
  lstatSync,
  mkdirSync as mkdirSync2,
  readdirSync,
  readFileSync as readFileSync4,
  readlinkSync,
  rmSync,
  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 (Boolean(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 == null || 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) {
    const fieldEntries = Object.entries(packageDeps(pkg, field));
    for (const [name, range] of fieldEntries) {
      Reflect.set(deps, `${field}:${name}`, range);
    }
  }
  return deps;
}
function workspaceDependencyNames(pkg, workspaceNames) {
  const names = /* @__PURE__ */ new Set();
  for (const field of workspaceDependencyFields) {
    const fieldEntries = Object.entries(packageDeps(pkg, field));
    for (const [name, range] of fieldEntries) {
      if (workspaceNames.has(name) && range.startsWith("workspace:")) {
        names.add(name);
      }
    }
  }
  return [...names].toSorted((a, b) => a.localeCompare(b));
}
function externalDeps(pkg, workspaceNames) {
  const deps = {};
  const depEntries = Object.entries(selectedDeps(pkg, dependencyFields));
  for (const [key, range] of depEntries) {
    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 = [];
  const entries = readdirSync(dir, { withFileTypes: true });
  for (const entry of entries) {
    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`);
  const sortedFiles = files.toSorted((a, b) => a.localeCompare(b));
  for (const file of sortedFiles) {
    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 (!Boolean(parsed) || typeof parsed !== "object") return {};
    const importers = parsed.importers;
    if (!Boolean(importers) || typeof importers !== "object" || Array.isArray(importers)) return {};
    const hashes = {};
    const sortedImporters = Object.entries(importers).toSorted(([a], [b]) => a.localeCompare(b));
    for (const [name, value] of sortedImporters) {
      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 = {};
  const sortedWorkspaces = workspaces.toSorted((a, b) => a.name.localeCompare(b.name));
  for (const workspace of sortedWorkspaces) {
    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 didWorkspaceNamesChange(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) {
    const nameDependents = dependents.get(name) ?? [];
    for (const dependent of nameDependents) {
      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 != null && workspaceName.length > 0)) {
      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 (didWorkspaceNamesChange(previous, current)) return "workspace set changed";
  if (previous.rootHash !== current.rootHash) return "root configuration changed";
  return void 0;
}
function isTrackingOutputs(action) {
  return action !== "lint";
}
function isExpandingDependents(action) {
  return action !== "lint";
}
function didWorkspaceChange(action, previous, current) {
  return previous.inputHash !== current.inputHash || isTrackingOutputs(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 === void 0) return { affected, fullReason: `workspace added: ${name}` };
    if (didWorkspaceChange(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,
    isVerbose,
    workspaces
  } = params;
  if (!previous) return fullPlan(action, current, previous, "no previous snapshot");
  const incompatible = compatibilityReason(previous, current);
  if (incompatible != null && incompatible.length > 0) return fullPlan(action, current, previous, incompatible);
  const { affected, fullReason } = collectChangedWorkspaceNames(action, previous, current);
  if (fullReason != null && fullReason.length > 0) return fullPlan(action, current, previous, fullReason);
  const lockImpact = resolveLockfileImpact(previous, current, workspaces);
  if (lockImpact.full != null && lockImpact.full.length > 0) return fullPlan(action, current, previous, lockImpact.full);
  for (const workspaceName of lockImpact.workspaceNames) {
    affected.add(workspaceName);
  }
  const affectedWorkspaceNames = isExpandingDependents(action) ? expandWithDependents(affected, workspaces) : [...affected].toSorted((a, b) => a.localeCompare(b));
  if ((isVerbose ?? false) && 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);
  mkdirSync2(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 path5 from "node:path";
import { pathToFileURL as pathToFileURL2 } from "node:url";
import chalk7 from "chalk";

// src/actions/lintTierAnalysis.ts
import { readFileSync as readFileSync5 } from "node:fs";
import { createRequire as createRequire2 } from "node:module";
import path4 from "node:path";
import { pathToFileURL } from "node:url";
import chalk6 from "chalk";
import { findUpSync } from "find-up";
var tierExportPattern = /config(?:React)?Tier\d+[A-Za-z]*/g;
function normalizeRuleLevel(setting) {
  let current = setting;
  while (Array.isArray(current) && current.length > 0) {
    current = current[0];
  }
  if (current === void 0) return "off";
  if (current === "off" || current === 0) return "off";
  if (current === "warn" || current === 1) return "warn";
  if (current === "error" || current === 2) return "error";
  return "off";
}
function countMessagesForTier(messages, rules) {
  let errors = 0;
  let warnings = 0;
  for (const message of messages) {
    if (message.ruleId === null) {
      errors++;
      continue;
    }
    const level = normalizeRuleLevel(rules[message.ruleId]);
    if (level === "off") continue;
    if (level === "error") errors++;
    else warnings++;
  }
  return { errors, warnings };
}
function getLintTierDefinitions(isReact, isTypeChecked) {
  if (isReact) {
    return [
      {
        id: 0,
        label: "Correctness",
        exportName: isTypeChecked ? "configReactTier0CorrectnessTypeChecked" : "configReactTier0Correctness"
      },
      {
        id: 1,
        label: "Consistency",
        exportName: isTypeChecked ? "configReactTier1ConsistencyTypeChecked" : "configReactTier1Consistency"
      },
      {
        id: 2,
        label: "Best Practices",
        exportName: isTypeChecked ? "configReactTier2BestPracticesTypeChecked" : "configReactTier2BestPractices"
      },
      {
        id: 3,
        label: "Opinionated",
        exportName: "configReactTier3OpinionatedTypeChecked"
      },
      {
        id: 4,
        label: "Experimental",
        exportName: isTypeChecked ? "configReactTier4ExperimentalTypeChecked" : "configReactTier4Experimental"
      }
    ];
  }
  return [
    {
      id: 0,
      label: "Correctness",
      exportName: isTypeChecked ? "configTier0CorrectnessTypeChecked" : "configTier0Correctness"
    },
    {
      id: 1,
      label: "Consistency",
      exportName: isTypeChecked ? "configTier1ConsistencyTypeChecked" : "configTier1Consistency"
    },
    {
      id: 2,
      label: "Best Practices",
      exportName: isTypeChecked ? "configTier2BestPracticesTypeChecked" : "configTier2BestPractices"
    },
    {
      id: 3,
      label: "Opinionated",
      exportName: isTypeChecked ? "configTier3OpinionatedTypeChecked" : "configTier3Opinionated"
    },
    {
      id: 4,
      label: "Experimental",
      exportName: isTypeChecked ? "configTier4ExperimentalTypeChecked" : "configTier4Experimental"
    }
  ];
}
function detectLintTierContext(cwd) {
  const configPath = findUpSync("eslint.config.ts", { cwd });
  if (configPath === void 0) {
    return {
      hasXylabsConfig: false,
      isReact: false,
      isTypeChecked: true
    };
  }
  const source = readFileSync5(configPath, "utf8");
  const hasXylabsConfig = source.includes("@xylabs/eslint-config-flat") || source.includes("@xylabs/eslint-config-react-flat");
  const isReact = source.includes("@xylabs/eslint-config-react-flat");
  const isTypeChecked = source.includes("TypeChecked");
  const tierMatches = source.match(tierExportPattern) ?? [];
  const currentTierExport = tierMatches.at(-1);
  return {
    currentTierExport,
    hasXylabsConfig,
    isReact,
    isTypeChecked
  };
}
async function loadXylabsEslintConfigPackage(cwd, isReact) {
  const packageName2 = isReact ? "@xylabs/eslint-config-react-flat" : "@xylabs/eslint-config-flat";
  const requireFromCwd = createRequire2(path4.join(cwd, "package.json"));
  const resolved = requireFromCwd.resolve(packageName2);
  return import(pathToFileURL(resolved).href);
}
function resolveTierConfigExport(configPackage, exportName) {
  const configs = configPackage[exportName];
  if (!Array.isArray(configs)) {
    throw new TypeError(`Missing ESLint tier export "${exportName}" from @xylabs/eslint-config`);
  }
  return configs;
}
function mergeTierRules(mergeConfigRules, configs) {
  return mergeConfigRules(configs);
}
async function loadMergeConfigRules(cwd) {
  const flatPackage = await loadXylabsEslintConfigPackage(cwd, false);
  const mergeConfigRules = flatPackage.mergeConfigRules;
  if (typeof mergeConfigRules !== "function") {
    throw new TypeError("mergeConfigRules is missing from @xylabs/eslint-config-flat");
  }
  return mergeConfigRules;
}
async function buildLintTierRuleMaps(cwd, context) {
  const configPackage = await loadXylabsEslintConfigPackage(cwd, context.isReact);
  const mergeConfigRules = await loadMergeConfigRules(cwd);
  const definitions = getLintTierDefinitions(context.isReact, context.isTypeChecked);
  const maps = /* @__PURE__ */ new Map();
  for (const definition of definitions) {
    const configs = resolveTierConfigExport(configPackage, definition.exportName);
    maps.set(definition.id, mergeTierRules(mergeConfigRules, configs));
  }
  return maps;
}
function projectLintTierCounts(messages, tierRuleMaps, definitions) {
  return definitions.map((definition) => {
    const rules = tierRuleMaps.get(definition.id) ?? {};
    const { errors, warnings } = countMessagesForTier(messages, rules);
    return {
      errors,
      label: definition.label,
      tier: definition.id,
      warnings
    };
  });
}
function formatLintTierAnalysisReport({
  context,
  counts,
  currentTierExport,
  files,
  timeMs
}) {
  const profile = [
    context.isReact ? "react" : "flat",
    context.isTypeChecked ? "type-checked" : "untyped"
  ].join(", ");
  const labelWidth = Math.max(...counts.map((entry) => entry.label.length), "Experimental".length);
  const lines = [
    chalk6.cyan("Lint tier analysis"),
    chalk6.gray(`XY preset projection (${profile}); based on your eslint.config.ts with no extra ESLint passes`),
    "",
    ` ${"Tier".padEnd(4)} ${"Preset".padEnd(labelWidth)}  ${"Errors".padStart(6)}  ${"Warnings".padStart(8)}`,
    ` ${"-".repeat(4)} ${"-".repeat(labelWidth)}  ${"-".repeat(6)}  ${"-".repeat(8)}`
  ];
  for (const entry of counts) {
    const definition = getLintTierDefinitions(context.isReact, context.isTypeChecked).find((tier) => tier.id === entry.tier);
    const isCurrent = definition?.exportName === currentTierExport || currentTierExport === void 0 && entry.tier === 3;
    const marker = isCurrent ? chalk6.gray("  <- current") : "";
    lines.push(
      ` ${String(entry.tier).padEnd(4)} ${entry.label.padEnd(labelWidth)}  ${String(entry.errors).padStart(6)}  ${String(entry.warnings).padStart(8)}${marker}`
    );
  }
  const currentTierId = getLintTierDefinitions(context.isReact, context.isTypeChecked).find((tier) => tier.exportName === currentTierExport)?.id;
  if (currentTierId !== void 0 && currentTierId < 4) {
    lines.push(
      "",
      chalk6.yellow("Note: eslint.config.ts is below tier 4. Counts for higher tiers only include violations ESLint reported with your current config and may be understated.")
    );
  }
  lines.push(
    "",
    chalk6.gray(`Analyzed ${files} files in ${timeMs < 1e3 ? `${timeMs}ms` : `${(timeMs / 1e3).toFixed(2)}s`}`)
  );
  return lines.join("\n");
}

// src/actions/lintNext.ts
var lintNextIgnorePatterns = ["packages/**"];
var lintNextResultMarker = "__XY_LINT_NEXT_RESULT__";
var require3 = createRequire3(import.meta.url);
var chalkImportUrl = pathToFileURL2(require3.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),
      )
    }
  }
}

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

try {
  const cwd = process.cwd()
  const engine = await createLintEngine(cwd)
  const lintResults = await engine.lintFiles('.')
  if (!options.analyze || options.verbose) {
    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
  const messages = options.analyze
    ? lintResults.flatMap((result) => result.messages.map((message) => ({
        ruleId: message.ruleId ?? null,
      })))
    : undefined

  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, messages, warnings }))
} catch (ex) {
  console.error(ex instanceof Error ? (ex.stack ?? ex.message) : String(ex))
  console.log(marker + JSON.stringify({ errors: 1, files: 0, messages: [], 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,
      messages: [],
      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,
      messages: parsed.messages ?? [],
      output: beforeMarker + remainingLines.join("\n"),
      warnings: parsed.warnings
    };
  } catch {
    return {
      errors: status === 0 ? 0 : 1,
      files: 0,
      messages: [],
      output,
      warnings: 0
    };
  }
}
async function lintOnePackageProcess({
  analyze,
  cache,
  cacheLocation,
  cwd,
  cycleDepth,
  fix,
  verbose
}) {
  return await new Promise((resolve) => {
    const output = [];
    const env = {
      ...process.env,
      FORCE_COLOR: "3",
      XY_LINT_NEXT_OPTIONS: JSON.stringify({
        analyze,
        cache,
        cacheLocation,
        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,
        messages: [],
        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}
`);
  }
}
function selectLintWorkspaces(allWorkspaces, pkg, targetWorkspaces) {
  if (pkg === void 0) return targetWorkspaces ?? allWorkspaces;
  const targetWorkspace = resolveWorkspace(allWorkspaces, pkg);
  return targetWorkspace === void 0 ? [] : [targetWorkspace];
}
function getLintLabel(isAnalyze, isFix, cycleDepth) {
  if (isAnalyze) return "Analyze";
  if (isFix) return "Fix";
  if (cycleDepth === void 0) return "Lint";
  return "Cycle";
}
function resolveAnalyzeContext(isAnalyze, rootDir) {
  if (!isAnalyze) return { kind: "disabled" };
  const tierContext = detectLintTierContext(rootDir);
  if (!tierContext.hasXylabsConfig) {
    console.error(chalk7.red("Lint tier analysis requires @xylabs/eslint-config-flat or @xylabs/eslint-config-react-flat in eslint.config.ts"));
    return { kind: "invalid" };
  }
  return { kind: "ready", tierContext };
}
async function printLintAnalyzeReport(rootDir, tierContext, totals, timeMs) {
  const tierRuleMaps = await buildLintTierRuleMaps(rootDir, tierContext);
  const definitions = getLintTierDefinitions(tierContext.isReact, tierContext.isTypeChecked);
  const tierCounts = projectLintTierCounts(totals.messages, tierRuleMaps, definitions);
  console.log(formatLintTierAnalysisReport({
    context: tierContext,
    counts: tierCounts,
    currentTierExport: tierContext.currentTierExport,
    files: totals.files,
    timeMs
  }));
}
function printLintSummary(totalErrors, totalWarnings, totalFiles, packageCount) {
  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 ${packageCount} packages`)
  );
  return actionResult({
    errorCount: totalErrors,
    exitCode: totalErrors + (isStrictMode() ? totalWarnings : 0),
    warningCount: totalWarnings
  });
}
function totalLintResults(results) {
  const total = {
    errors: 0,
    files: 0,
    messages: [],
    warnings: 0
  };
  for (const result of results) {
    total.errors += result.errors;
    total.files += result.files;
    total.warnings += result.warnings;
    total.messages.push(...result.messages);
  }
  return total;
}
async function lintNext({
  analyze = false,
  cache = false,
  cycleDepth,
  fix = false,
  jobs,
  pkg,
  verbose = false,
  workspaces: targetWorkspaces
}) {
  const rootDir = INIT_CWD();
  const analyzeContext = resolveAnalyzeContext(analyze, rootDir);
  if (analyzeContext.kind === "invalid") {
    return resultFromExitCode(1);
  }
  const tierContext = analyzeContext.kind === "ready" ? analyzeContext.tierContext : void 0;
  const pm = getPackageManager();
  const allWorkspaces = pm.listWorkspaces();
  const workspaces = selectLintWorkspaces(allWorkspaces, pkg, targetWorkspaces);
  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 != null && pkg.length > 0 ? `Package "${pkg}" not found` : "No workspaces found"));
    return resultFromExitCode(1);
  }
  const concurrency = jobs;
  const label = getLintLabel(analyze, fix, cycleDepth);
  const analyzeStarted = Date.now();
  const results = Array.from(
    { length: workspaces.length },
    () => ({
      errors: 0,
      files: 0,
      messages: [],
      output: "",
      pkg: "",
      timeMs: 0,
      warnings: 0
    })
  );
  await runWithConcurrency(
    workspaces.map((ws, i) => ({ i, ws })),
    concurrency,
    async ({ i, ws }) => {
      const pkgStart = Date.now();
      const absCwd = path5.resolve(rootDir, ws.location);
      const cacheLocation = cache ? workspaceEslintCachePath(rootDir, ws.location) : void 0;
      if (cacheLocation !== void 0) ensureEslintCacheDir(cacheLocation);
      const {
        errors,
        files,
        messages,
        output,
        warnings
      } = await lintOnePackageProcess({
        analyze,
        cache,
        cacheLocation,
        cwd: absCwd,
        cycleDepth,
        fix,
        verbose
      });
      const result = {
        errors,
        files,
        messages,
        output,
        pkg: ws.name,
        timeMs: Date.now() - pkgStart,
        warnings
      };
      results[i] = result;
      printPackageResult(label, result);
    }
  );
  const {
    errors: totalErrors,
    files: totalFiles,
    messages: totalMessages,
    warnings: totalWarnings
  } = totalLintResults(results);
  if (analyze && tierContext !== void 0) {
    await printLintAnalyzeReport(rootDir, tierContext, {
      files: totalFiles,
      messages: totalMessages
    }, Date.now() - analyzeStarted);
    return 0;
  }
  return printLintSummary(totalErrors, totalWarnings, totalFiles, workspaces.length);
}

// 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 !== false;
}
function shouldUseIncrementalLint({
  analyze,
  fix,
  incremental,
  pkg
}) {
  return pkg === void 0 && fix !== true && analyze !== true && shouldUseIncremental(incremental);
}
function lintOptionsHash({ cycleDepth }) {
  return {
    cycleDepth,
    strict: isStrictMode()
  };
}
var lintPackage = ({
  pkg,
  fix,
  verbose
}) => {
  const pm = getPackageManager();
  return runSteps(`${fix ?? false ? "Fix" : "Lint"} [${pkg}]`, [
    pm.runInWorkspace(pkg, fix ?? false ? "package-fix" : verbose ?? false ? "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({ cycleDepth }),
    pm,
    isVerbose: verbose,
    workspaces: allWorkspaces
  });
  if (plan.full && (plan.reason != null && plan.reason.length > 0)) {
    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({ cycleDepth }),
      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({ cycleDepth }),
      pm,
      workspaces: allWorkspaces
    });
  }
  return result;
}
var lint = ({
  analyze,
  cache,
  cycleDepth,
  fix,
  incremental,
  jobs,
  prev,
  pkg,
  verbose,
  workspaces
}) => {
  if (analyze === true && fix === true) {
    console.error("The --analyze option cannot be combined with --fix");
    return 1;
  }
  if (!(prev ?? false)) {
    if (shouldUseIncrementalLint({
      analyze,
      fix,
      incremental,
      pkg
    })) {
      return lintIncremental({
        cache,
        cycleDepth,
        fix,
        jobs,
        verbose,
        workspaces
      });
    }
    const params = {
      analyze,
      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 cycle = ({
  cache,
  depth = 25,
  jobs,
  pkg,
  verbose
}) => {
  return lint({
    cache,
    cycleDepth: depth,
    jobs,
    pkg,
    verbose
  });
};
var lintAllPackages = ({ fix = false } = {}) => {
  const rootDir = INIT_CWD();
  const cachePath = workspaceEslintCachePath(rootDir, ".");
  ensureEslintCacheDir(cachePath);
  const fixOptions = fix ? ["--fix"] : [];
  const strictOptions = isStrictMode() ? ["--max-warnings", "0"] : [];
  return runSteps(`${fix ? "Fix" : "Lint"} [All-Packages]`, [
    ["eslint", ["--cache", "--cache-location", cachePath, "--cache-strategy", "content", ...fixOptions, ...strictOptions]]
  ]);
};

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

// src/xy/lint/cycleCommand.ts
var cycleCommand = {
  command: "cycle [package]",
  describe: "Cycle - Run ESLint with import cycle checking",
  builder: (yargs) => {
    return packagePositionalParam(yargs).option("cache", {
      alias: "c",
      default: false,
      description: "Use caching for performance",
      type: "boolean"
    }).option("depth", {
      default: 25,
      description: "Maximum import depth for import-x/no-cycle",
      type: "number"
    }).check((argv) => {
      const depth = argv.depth;
      if (!Number.isSafeInteger(depth) || depth < 1) {
        throw new Error("--depth must be a positive integer");
      }
      return true;
    });
  },
  handler: async (argv) => {
    if (Boolean(argv.verbose)) console.log("Cycle");
    await withEnvelope("cycle", () => cycle({
      cache: argv.cache,
      depth: argv.depth,
      jobs: argv.jobs,
      pkg: argv.package,
      verbose: !!Boolean(argv.verbose)
    }));
  }
};
export {
  cycleCommand
};
//# sourceMappingURL=cycleCommand.mjs.map
