// src/actions/compile.ts
import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
import path3 from "node:path";
import chalk6 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", 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/lib/packageManagerRuntime.ts
import fs from "node:fs";
import chalk2 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(chalk2.yellow(`${DISPLAY_NAMES[plan.packageManager]} is required for "${context.operation}".`));
  for (const line of plan.manualInstructions) {
    console.error(chalk2.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(chalk2.yellow(`${context.operation} requires ${displayName}, but it is not installed.`));
  if (!plan.supported) {
    printManualInstructions(plan, context);
    return false;
  }
  if (!isCommandInstalled("brew")) {
    console.error(chalk2.yellow("Homebrew is not installed, so automatic installation is unavailable."));
    console.error(chalk2.gray("  Install Homebrew from https://brew.sh and then run:"));
    console.error(chalk2.gray(`  ${plan.command}`));
    return false;
  }
  const isConfirmed = shouldAskYesNo(chalk2.cyan(`Install ${displayName} with Homebrew now? [y/N] `));
  if (!isConfirmed) {
    console.error(chalk2.gray(`Skipping install. Run "${plan.command}" manually and then retry.`));
    return false;
  }
  console.error(chalk2.cyan(`Installing ${displayName} via Homebrew...
`));
  if (!shouldInstallWithHomebrew(pm, context.cwd)) {
    console.error(chalk2.red(`Homebrew failed to install ${displayName}.`));
    console.error(chalk2.gray(`Run "${plan.command}" manually and then retry.`));
    return false;
  }
  if (!isPackageManagerInstalled(pm)) {
    console.error(chalk2.red(`${displayName} still does not appear to be installed after Homebrew completed.`));
    console.error(chalk2.gray(`Run "${plan.command}" manually and then retry.`));
    return false;
  }
  console.error(chalk2.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(path4) {
  if (!existsSync(path4)) return void 0;
  try {
    return JSON.parse(readFileSync(path4, "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 chalk3 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(chalk3.red(`'${error2.path}' not found.`));
    } else {
      console.error(chalk3.red(`Errno: ${error2.code}`));
    }
    return error2.errno ?? -1;
  }) ?? withError(error, (error2) => {
    console.error(chalk3.red(`${error2.name}: ${error2.message}`));
    return -1;
  }) ?? (() => {
    console.error(chalk3.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);
  }
};
var safeExitAsync = async (func, shouldExitOnFail = true) => {
  try {
    const result = await 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/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 != null && process.env.npm_package_name.length > 0) {
    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/xyReporter.ts
var reporterState = {
  currentCommand: "unknown",
  isEnvelopeEmitted: false,
  isJsonModeEnabled: false,
  isStrictModeEnabled: false,
  originalStdoutWrite: void 0,
  startTime: 0
};
function isJsonMode() {
  return reporterState.isJsonModeEnabled;
}

// src/lib/runSteps.ts
import { existsSync as existsSync3 } from "node:fs";
import chalk4 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(chalk4.green(`${name} [${pkgName}]`));
    let totalStatus = 0;
    for (const [i, [command, args, config]] of steps.entries()) {
      if (messages && Object.hasOwn(messages, i)) {
        console.log(chalk4.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/lib/runStepsAsync.ts
import { existsSync as existsSync4 } from "node:fs";
import chalk5 from "chalk";
var packageManagers2 = /* @__PURE__ */ new Set(["bun", "npm", "pnpm", "yarn"]);
var runStepAsync = (name, step, shouldExitOnFail = true, message) => {
  return new Promise((resolve) => {
    const [command, args, config] = step;
    if (message != null && message.length > 0) {
      console.log(chalk5.gray(message));
    }
    const argList = Array.isArray(args) ? args : args.split(" ");
    if (command === "node" && !existsSync4(argList[0])) {
      throw new Error(`File not found [${argList[0]}]`);
    }
    if (packageManagers2.has(command) && !didEnsurePackageManagerInstalled(command, { operation: `${name}: ${command} ${Array.isArray(args) ? args.join(" ") : args}`.trim() })) {
      checkResult(name, 1, "error", shouldExitOnFail);
      resolve(1);
      return;
    }
    spawn(command, Array.isArray(args) ? args : args.split(" "), {
      ...config,
      env: { FORCE_COLOR: "3", ...process.env },
      stdio: isJsonMode() ? ["inherit", 2, 2] : "inherit"
    }).on("close", (code) => {
      if (code != null && !Number.isNaN(code) && code !== 0) {
        const argsText = Array.isArray(args) ? args.join(" ") : args;
        const message2 = `Command Exited With Non-Zero Result [${chalk5.gray(code)}] | ${chalk5.yellow(command)} ${chalk5.white(argsText)}`;
        console.error(chalk5.red(message2));
        checkResult(name, code, "error", shouldExitOnFail);
        resolve(code);
      } else {
        resolve(0);
      }
    });
  });
};

// src/actions/incremental.ts
import { createHash } from "node:crypto";
import {
  existsSync as existsSync5,
  lstatSync,
  mkdirSync,
  readdirSync,
  readFileSync as readFileSync4,
  readlinkSync,
  rmSync,
  writeFileSync
} from "node:fs";
import path2 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(path2.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(path2.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 (!existsSync5(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(path2.join(dir, entry.name), baseDir));
      }
      continue;
    }
    if (!entry.isFile() && !entry.isSymbolicLink()) continue;
    if (ignoredInputFiles.has(entry.name)) continue;
    const relativePath = path2.relative(baseDir, path2.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 = path2.join(workspaceDir, outputDir);
    if (existsSync5(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 = path2.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 = path2.resolve(rootDir, workspace.location);
  return hashFiles(workspaceDir, collectFiles(workspaceDir));
}
function workspaceOutputHash(rootDir, workspace) {
  const workspaceDir = path2.resolve(rootDir, workspace.location);
  return hashFiles(workspaceDir, collectOutputFiles(workspaceDir));
}
function rootHash(rootDir) {
  return hashFiles(rootDir, rootConfigFiles(rootDir));
}
function lockfileHash(rootDir, pm) {
  const lockfilePath = path2.resolve(rootDir, pm.lockfile);
  return existsSync5(lockfilePath) ? hashContent(readFileSync4(lockfilePath)) : "";
}
function readPnpmLockfileImporters(rootDir, pm) {
  if (pm.name !== "pnpm") return {};
  const lockfilePath = path2.resolve(rootDir, pm.lockfile);
  if (!existsSync5(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 = path2.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: existsSync5(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 path2.resolve(rootDir, ".xy/cache/incremental", `${action}.json`);
}
function readSnapshot(action) {
  const filePath = snapshotPath(INIT_CWD(), action);
  if (!existsSync5(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);
  mkdirSync(path2.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
  });
}

// src/actions/compile.ts
function isWorkspaceRange(value) {
  return typeof value === "string" && value.startsWith("workspace:");
}
function readWorkspacePackageJson(rootDir, workspace) {
  const packageJsonPath = path3.resolve(rootDir, workspace.location, "package.json");
  return JSON.parse(readFileSync5(packageJsonPath, "utf8"));
}
function readRootWorkspace(rootDir) {
  const packageJsonPath = path3.resolve(rootDir, "package.json");
  if (!existsSync6(packageJsonPath)) return void 0;
  const packageJson = JSON.parse(readFileSync5(packageJsonPath, "utf8"));
  if (!(packageJson.name != null && packageJson.name.length > 0)) return void 0;
  return {
    listed: false,
    location: ".",
    name: packageJson.name,
    packageJson
  };
}
function allCompileWorkspaces(pm) {
  const rootDir = INIT_CWD();
  const workspaces = pm.listWorkspaces();
  return workspaces.map((workspace) => ({
    ...workspace,
    listed: true,
    packageJson: readWorkspacePackageJson(rootDir, workspace)
  }));
}
function emitWorkspaces(pm) {
  const rootDir = INIT_CWD();
  const workspaces = allCompileWorkspaces(pm);
  const nonRootWorkspaces = workspaces.filter((workspace) => workspace.location !== ".");
  if (nonRootWorkspaces.length > 0) return nonRootWorkspaces;
  if (workspaces.length > 0) return workspaces;
  const rootWorkspace = readRootWorkspace(rootDir);
  return rootWorkspace ? [rootWorkspace] : [];
}
function validationWorkspaces(pm) {
  const rootDir = INIT_CWD();
  const allWorkspaces = allCompileWorkspaces(pm);
  const rootWorkspace = allWorkspaces.find((workspace) => workspace.location === ".") ?? readRootWorkspace(rootDir);
  const workspaces = allWorkspaces.filter((workspace) => workspace.location !== ".");
  return rootWorkspace ? [rootWorkspace, ...workspaces] : workspaces;
}
function packageScriptStep(pm, workspace, script, args) {
  return workspace.location === "." && workspace.listed !== true ? [script, args] : pm.runInWorkspaceByName(workspace.name, script, args);
}
function getWorkspaceDependencyNames(workspace, workspaceNames, fields) {
  const names = /* @__PURE__ */ new Set();
  for (const field of fields) {
    const fieldEntries = Object.entries(workspace.packageJson[field] ?? {});
    for (const [name, range] of fieldEntries) {
      if (name !== workspace.name && workspaceNames.has(name) && isWorkspaceRange(range)) {
        names.add(name);
      }
    }
  }
  return [...names].toSorted((a, b) => a.localeCompare(b));
}
function tarjanStronglyConnectedComponents(nodes, edges) {
  const indexMap = /* @__PURE__ */ new Map();
  const lowlink = /* @__PURE__ */ new Map();
  const onStack = /* @__PURE__ */ new Set();
  const stack = [];
  const sccs = [];
  let nextIndex = 0;
  const strongConnect = (v) => {
    indexMap.set(v, nextIndex);
    lowlink.set(v, nextIndex);
    nextIndex += 1;
    stack.push(v);
    onStack.add(v);
    const neighbors = edges.get(v) ?? [];
    for (const w of neighbors) {
      if (!indexMap.has(w)) {
        strongConnect(w);
        lowlink.set(v, Math.min(lowlink.get(v) ?? 0, lowlink.get(w) ?? 0));
      } else if (onStack.has(w)) {
        lowlink.set(v, Math.min(lowlink.get(v) ?? 0, indexMap.get(w) ?? 0));
      }
    }
    if (lowlink.get(v) === indexMap.get(v)) {
      const scc = [];
      let popped;
      do {
        popped = stack.pop();
        if (popped === void 0) break;
        onStack.delete(popped);
        scc.push(popped);
      } while (popped !== v);
      sccs.push(scc);
    }
  };
  for (const v of nodes) {
    if (!indexMap.has(v)) {
      strongConnect(v);
    }
  }
  return sccs;
}
function edgeKey(from, to) {
  return `${from} ${to}`;
}
function dropDevDepEdgesInScc(scc, dependencies, strictEdges) {
  const sccSet = new Set(scc);
  for (const from of scc) {
    const outgoing = dependencies.get(from);
    if (!outgoing) continue;
    const removable = [];
    for (const to of outgoing) {
      if (sccSet.has(to) && !strictEdges.has(edgeKey(from, to))) {
        removable.push(to);
      }
    }
    for (const to of removable) outgoing.delete(to);
  }
}
function breakDevDependencyCycles(nodeNames, dependencies, strictEdges) {
  const sccs = tarjanStronglyConnectedComponents(nodeNames, dependencies);
  for (const scc of sccs) {
    if (scc.length >= 2) dropDevDepEdgesInScc(scc, dependencies, strictEdges);
  }
  const residualSccs = tarjanStronglyConnectedComponents(nodeNames, dependencies);
  for (const scc of residualSccs) {
    if (scc.length > 1) {
      const cycle = scc.toSorted((a, b) => a.localeCompare(b)).join(" -> ");
      throw new Error(`workspace dependency cycle in 'dependencies': ${cycle}`);
    }
  }
}
function collectWorkspaceEdges(workspaces, workspaceNames, fields) {
  const dependencies = /* @__PURE__ */ new Map();
  const strictEdges = /* @__PURE__ */ new Set();
  for (const workspace of workspaces) {
    dependencies.set(workspace.name, /* @__PURE__ */ new Set());
  }
  for (const workspace of workspaces) {
    for (const field of fields) {
      const workspaceDeps = Object.entries(workspace.packageJson[field] ?? {}).filter(
        ([name, range]) => name !== workspace.name && workspaceNames.has(name) && isWorkspaceRange(range)
      );
      for (const [name] of workspaceDeps) {
        dependencies.get(workspace.name)?.add(name);
        if (field === "dependencies") {
          strictEdges.add(edgeKey(workspace.name, name));
        }
      }
    }
  }
  return { dependencies, strictEdges };
}
function createWorkspaceDependencyGraph(workspaces, fields) {
  const workspacesByName = new Map(workspaces.map((workspace) => [workspace.name, workspace]));
  const workspaceNames = new Set(workspacesByName.keys());
  const { dependencies, strictEdges } = collectWorkspaceEdges(workspaces, workspaceNames, fields);
  const dependents = /* @__PURE__ */ new Map();
  for (const workspace of workspaces) {
    dependents.set(workspace.name, /* @__PURE__ */ new Set());
  }
  breakDevDependencyCycles([...workspaceNames], dependencies, strictEdges);
  for (const [workspaceName, dependencyNames] of dependencies) {
    for (const dependencyName of dependencyNames) {
      dependents.get(dependencyName)?.add(workspaceName);
    }
  }
  return {
    dependencies,
    dependents,
    workspacesByName
  };
}
async function runWorkspaceScripts(label, pm, workspaces, script, args, jobs) {
  const results = Array.from({ length: workspaces.length }, () => 0);
  await runWithConcurrency(
    workspaces.map((workspace, index) => ({ index, workspace })),
    Math.max(1, jobs),
    async ({ index, workspace }) => {
      results[index] = await runStepAsync(label, packageScriptStep(pm, workspace, script, args), false);
    }
  );
  return results.reduce((total, result) => total + result, 0);
}
function selectedWorkspaces(workspaces, names) {
  const selected = new Set(names);
  return workspaces.filter((workspace) => selected.has(workspace.name));
}
function shouldUseIncremental(incremental) {
  return incremental !== false;
}
function createCompilePlan({
  incrementalPlan,
  pm,
  shouldUseIncremental: shouldUseIncremental2,
  isVerbose,
  workspaces
}) {
  if (!shouldUseIncremental2) return void 0;
  return incrementalPlan ?? createIncrementalPlan({
    action: "compile",
    pm,
    isVerbose,
    workspaces
  });
}
function logCompilePlan(shouldUseIncremental2, plan) {
  const targetNames = plan?.affectedWorkspaceNames;
  const label = shouldUseIncremental2 ? "Compile-Incremental" : "Compile";
  console.log(chalk6.green(`${label} [${targetNames ? targetNames.length : "All"}] [${packageName()}]`));
  if (plan !== void 0 && plan.full && (plan.reason != null && plan.reason.length > 0)) {
    console.log(chalk6.gray(`  Full compile: ${plan.reason}`));
  }
}
function hasPlanWithNoChanges(shouldUseIncremental2, plan) {
  return shouldUseIncremental2 && plan !== void 0 && !plan.full && plan.affectedWorkspaceNames.length === 0;
}
function compileTargetWorkspaces(allWorkspaces, targetNames, full) {
  return targetNames === void 0 || (full ?? false) ? allWorkspaces : selectedWorkspaces(allWorkspaces, targetNames);
}
async function runCompileAll({
  incremental,
  incrementalPlan,
  jobs,
  pm,
  isVerbose
}) {
  const verboseOptions = isVerbose ?? false ? ["-v"] : [];
  const isUseIncremental = shouldUseIncremental(incremental);
  const allValidationWorkspaces = validationWorkspaces(pm);
  const plan = createCompilePlan({
    incrementalPlan,
    pm,
    shouldUseIncremental: isUseIncremental,
    isVerbose,
    workspaces: allValidationWorkspaces
  });
  const targetNames = plan?.affectedWorkspaceNames;
  logCompilePlan(isUseIncremental, plan);
  if (hasPlanWithNoChanges(isUseIncremental, plan)) {
    console.log(chalk6.gray("  No changed packages to compile."));
    writeIncrementalSnapshot({
      action: "compile",
      pm,
      workspaces: allValidationWorkspaces
    });
    return 0;
  }
  const emitResult = await runWorkspaceScriptsTopologically(
    "Compile:Emit",
    pm,
    compileTargetWorkspaces(emitWorkspaces(pm), targetNames, plan?.full),
    ["dependencies", "devDependencies"],
    "package-compile",
    ["--emit-only", ...verboseOptions],
    jobs
  );
  if (emitResult !== 0) return resultFromExitCode(emitResult);
  const validateResult = await runWorkspaceScripts(
    "Compile:Validate",
    pm,
    compileTargetWorkspaces(allValidationWorkspaces, targetNames, plan?.full),
    "package-compile",
    ["--validate-only", ...verboseOptions],
    jobs
  );
  if (validateResult === 0) {
    writeIncrementalSnapshot({
      action: "compile",
      pm,
      workspaces: allValidationWorkspaces
    });
  }
  return resultFromExitCode(validateResult);
}
async function runWorkspaceScriptsTopologically(label, pm, workspaces, fields, script, args, jobs) {
  const {
    dependencies,
    dependents,
    workspacesByName
  } = createWorkspaceDependencyGraph(workspaces, fields);
  const pendingDependencies = new Map(
    [...dependencies].map(([workspaceName, dependencyNames]) => [workspaceName, dependencyNames.size])
  );
  const ready = [...pendingDependencies].filter(([, count]) => count === 0).map(([workspaceName]) => workspaceName).toSorted((a, b) => a.localeCompare(b));
  const concurrency = Math.max(1, jobs);
  let active = 0;
  let completed = 0;
  let isStopped = false;
  let totalStatus = 0;
  return await new Promise((resolve) => {
    const finishIfDone = () => {
      if ((completed === workspaces.length || isStopped) && active === 0) {
        if (!isStopped && ready.length === 0 && completed < workspaces.length) {
          console.error(chalk6.red(`${label}: workspace dependency cycle detected`));
          resolve(totalStatus + 1);
          return true;
        }
        resolve(totalStatus);
        return true;
      }
      if (!isStopped && ready.length === 0 && active === 0 && completed < workspaces.length) {
        console.error(chalk6.red(`${label}: workspace dependency cycle detected`));
        resolve(totalStatus + 1);
        return true;
      }
      return false;
    };
    const launch = () => {
      if (finishIfDone()) return;
      while (!isStopped && active < concurrency && ready.length > 0) {
        const workspaceName = ready.shift();
        if (workspaceName === void 0) continue;
        const workspace = workspacesByName.get(workspaceName);
        if (!workspace) continue;
        active += 1;
        void (async () => {
          try {
            const status = await runStepAsync(label, packageScriptStep(pm, workspace, script, args), false);
            active -= 1;
            completed += 1;
            totalStatus += status;
            if (status === 0) {
              const workspaceDependents = dependents.get(workspace.name) ?? [];
              for (const dependentName of workspaceDependents) {
                const nextCount = (pendingDependencies.get(dependentName) ?? 0) - 1;
                pendingDependencies.set(dependentName, nextCount);
                if (nextCount === 0) {
                  ready.push(dependentName);
                }
              }
              ready.sort((a, b) => a.localeCompare(b));
            } else {
              isStopped = true;
            }
          } catch (reason) {
            active -= 1;
            completed += 1;
            isStopped = true;
            totalStatus += 1;
            console.error(chalk6.red(`${label}: ${reason.message}`));
          }
          launch();
        })();
      }
    };
    launch();
  });
}
var compile = ({
  isVerbose,
  pkg,
  incremental,
  jobs,
  incrementalPlan,
  shouldExitOnFail
}) => {
  return pkg != null && pkg.length > 0 ? compilePackage({
    shouldExitOnFail,
    pkg,
    isVerbose
  }) : compileAll({
    shouldExitOnFail,
    incremental,
    incrementalPlan,
    jobs,
    isVerbose
  });
};
var compilePackage = ({
  shouldExitOnFail,
  pkg,
  isVerbose
}) => {
  const pm = getPackageManager();
  const verboseOptions = isVerbose ?? false ? ["-v"] : [];
  const steps = [pm.runInWorkspace(pkg, "package-compile", verboseOptions)];
  if (shouldExitOnFail === void 0) {
    return resultFromExitCode(runSteps(`Compile [${pkg}]`, steps));
  }
  return resultFromExitCode(runSteps(
    `Compile [${pkg}]`,
    steps,
    shouldExitOnFail
  ));
};
var compileAll = ({
  shouldExitOnFail,
  jobs,
  isVerbose,
  incremental,
  incrementalPlan
}) => {
  const pm = getPackageManager();
  const action = () => runCompileAll({
    shouldExitOnFail,
    incremental,
    incrementalPlan,
    jobs,
    pm,
    isVerbose
  });
  return shouldExitOnFail === void 0 ? safeExitAsync(action) : safeExitAsync(action, shouldExitOnFail);
};
export {
  allCompileWorkspaces,
  compile,
  compileAll,
  compilePackage,
  createWorkspaceDependencyGraph,
  emitWorkspaces,
  getWorkspaceDependencyNames,
  validationWorkspaces
};
//# sourceMappingURL=compile.mjs.map
