// 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(path3) {
  if (!existsSync(path3)) return void 0;
  try {
    return JSON.parse(readFileSync(path3, "utf8"));
  } catch {
    return void 0;
  }
}
function readRootPackageJson(cwd = process.cwd()) {
  return readJsonFile(PATH.resolve(cwd, "package.json"));
}
function readWorkspacePatternsFromPackageJson(cwd = process.cwd()) {
  const pkg = readRootPackageJson(cwd);
  if (!pkg?.workspaces) return [];
  if (Array.isArray(pkg.workspaces)) return [...pkg.workspaces];
  return pkg.workspaces.packages ? [...pkg.workspaces.packages] : [];
}
function readPnpmWorkspacePatterns(cwd = process.cwd()) {
  const wsPath = PATH.resolve(cwd, "pnpm-workspace.yaml");
  if (!existsSync(wsPath)) return [];
  const content = readFileSync(wsPath, "utf8");
  const patterns = [];
  let isInPackages = false;
  for (const line of content.split("\n")) {
    if (/^packages\s*:/.test(line.trim())) {
      isInPackages = true;
      continue;
    }
    if (isInPackages) {
      const match = /^\s+-\s+['"]?([^'"]+)['"]?\s*$/.exec(line);
      if (match) {
        patterns.push(match[1]);
      } else if (line.trim() !== "" && !/^\s/.test(line)) {
        break;
      }
    }
  }
  return patterns;
}
function readWorkspacePatterns(cwd = process.cwd()) {
  const fromPackageJson = readWorkspacePatternsFromPackageJson(cwd);
  return fromPackageJson.length > 0 ? fromPackageJson : readPnpmWorkspacePatterns(cwd);
}
function workspaceFromPackageJsonMatch(match, cwd, seen) {
  const pkg = readJsonFile(match);
  const name = pkg?.name;
  if (name === void 0 || name.length === 0) return void 0;
  const location = PATH.relative(cwd, PATH.dirname(match)) || ".";
  if (seen.has(location)) return void 0;
  seen.add(location);
  return { location, name };
}
function listDeclaredWorkspaces(cwd = process.cwd()) {
  const patterns = readWorkspacePatterns(cwd);
  const seen = /* @__PURE__ */ new Set();
  const workspaces = [];
  for (const pattern of patterns) {
    const matches = globSync(PATH.posix.join(pattern.replaceAll(PATH.sep, "/"), "package.json"), {
      absolute: true,
      cwd,
      ignore: ["**/node_modules/**", "**/dist/**", "**/build/**"]
    });
    for (const match of matches) {
      const workspace = workspaceFromPackageJsonMatch(match, cwd, seen);
      if (workspace) workspaces.push(workspace);
    }
  }
  return workspaces.toSorted((a, b) => a.location.localeCompare(b.location));
}
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);
  }
};

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

// src/lib/match.ts
import { minimatch } from "minimatch";
function makeMatcher(pattern, options = {}) {
  const patterns = Array.isArray(pattern) ? pattern : [pattern];
  return (input) => patterns.some((p) => minimatch(input, p, options));
}

// src/lib/packageName.ts
import { readFileSync as readFileSync2 } 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(readFileSync2(pkgPath, "utf8"));
    return pkg.name;
  } catch {
    return void 0;
  }
}

// src/lib/pnpmConfig/readMinReleaseAge.ts
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
import os from "node:os";
import PATH2 from "node:path";
import * as yaml from "yaml";
var DEFAULT_MINIMUM_RELEASE_AGE_MINUTES = 1440;
function emptySource() {
  return {
    excludeSet: void 0,
    ignoreMissingTime: void 0,
    minutes: void 0,
    strict: void 0
  };
}
function coerceNumber(value) {
  if (typeof value === "number" && Number.isFinite(value)) return value;
  if (typeof value === "string" && value.trim() !== "") {
    const n = Number(value);
    return Number.isFinite(n) ? n : void 0;
  }
  return void 0;
}
function coerceBoolean(value) {
  if (typeof value === "boolean") return value;
  if (typeof value === "string") {
    const lower = value.trim().toLowerCase();
    if (lower === "true") return true;
    if (lower === "false") return false;
  }
  return void 0;
}
function coerceStringArray(value) {
  if (Array.isArray(value)) {
    return value.filter((v) => typeof v === "string" && v.length > 0);
  }
  if (typeof value === "string") {
    return value.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
  }
  return void 0;
}
function readWorkspaceYaml(filePath) {
  const out = emptySource();
  if (!existsSync3(filePath)) return out;
  let parsed;
  try {
    parsed = yaml.parse(readFileSync3(filePath, "utf8"));
  } catch {
    return out;
  }
  if (parsed === null || typeof parsed !== "object") return out;
  const obj = parsed;
  out.minutes = coerceNumber(obj.minimumReleaseAge);
  out.excludeSet = coerceStringArray(obj.minimumReleaseAgeExclude);
  out.ignoreMissingTime = coerceBoolean(obj.minimumReleaseAgeIgnoreMissingTime);
  out.strict = coerceBoolean(obj.minimumReleaseAgeStrict);
  return out;
}
function applyNpmrcKey(out, key, value) {
  switch (key) {
    case "minimum-release-age":
    case "minimumreleaseage": {
      const n = coerceNumber(value);
      if (n !== void 0) out.minutes = n;
      return;
    }
    case "minimum-release-age-exclude":
    case "minimumreleaseageexclude": {
      const arr = coerceStringArray(value);
      if (arr !== void 0) out.excludeSet = arr;
      return;
    }
    case "minimum-release-age-ignore-missing-time":
    case "minimumreleaseageignoremissingtime": {
      const b = coerceBoolean(value);
      if (b !== void 0) out.ignoreMissingTime = b;
      return;
    }
    case "minimum-release-age-strict":
    case "minimumreleaseagestrict": {
      const b = coerceBoolean(value);
      if (b !== void 0) out.strict = b;
    }
  }
}
function readNpmrc(filePath) {
  const out = emptySource();
  if (!existsSync3(filePath)) return out;
  let text;
  try {
    text = readFileSync3(filePath, "utf8");
  } catch {
    return out;
  }
  for (const rawLine of text.split("\n")) {
    const line = rawLine.trim();
    if (!line || line.startsWith("#") || line.startsWith(";")) continue;
    const eq = line.indexOf("=");
    if (eq === -1) continue;
    const key = line.slice(0, eq).trim().toLowerCase();
    const value = line.slice(eq + 1).trim().replaceAll(/^["']|["']$/g, "");
    applyNpmrcKey(out, key, value);
  }
  return out;
}
function merge(primary, fallback) {
  return {
    minutes: primary.minutes ?? fallback.minutes,
    excludeSet: primary.excludeSet ?? fallback.excludeSet,
    ignoreMissingTime: primary.ignoreMissingTime ?? fallback.ignoreMissingTime,
    strict: primary.strict ?? fallback.strict
  };
}
function readMinReleaseAgeConfig(cwd) {
  const workspace = readWorkspaceYaml(PATH2.resolve(cwd, "pnpm-workspace.yaml"));
  const projectNpmrc = readNpmrc(PATH2.resolve(cwd, ".npmrc"));
  const userNpmrc = readNpmrc(PATH2.resolve(os.homedir(), ".npmrc"));
  const merged = merge(merge(workspace, projectNpmrc), userNpmrc);
  return {
    minutes: merged.minutes,
    exclude: merged.excludeSet ?? [],
    ignoreMissingTime: merged.ignoreMissingTime ?? true,
    strict: merged.strict ?? true
  };
}

// 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 existsSync4 } 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" && !existsSync4(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/updo/applyUpdates.ts
import { readFileSync as readFileSync4, writeFileSync } from "node:fs";
import PATH3 from "node:path";
import chalk5 from "chalk";
import semver from "semver";
function isSimpleRange(range) {
  const trimmed = range.trim();
  if (trimmed.startsWith("^") || trimmed.startsWith("~")) return true;
  return semver.valid(trimmed) !== null;
}
function shouldApplyToBag(bag, updateMap) {
  if (!bag) return false;
  let isChanged = false;
  for (const name of Object.keys(bag)) {
    const update = updateMap.get(name);
    if (!update) continue;
    if (bag[name] !== update.targetRange) {
      bag[name] = update.targetRange;
      isChanged = true;
    }
  }
  return isChanged;
}
function shouldApplyToPeerBag(pkg, updateMap) {
  const peer = pkg.peerDependencies;
  if (peer === void 0) return false;
  let isChanged = false;
  for (const name of Object.keys(peer)) {
    const update = updateMap.get(name);
    if (!update) continue;
    if (pkg.dependencies?.[name] !== void 0) continue;
    if (pkg.devDependencies?.[name] !== void 0) continue;
    if (!isSimpleRange(peer[name])) continue;
    if (peer[name] !== update.targetRange) {
      peer[name] = update.targetRange;
      isChanged = true;
    }
  }
  return isChanged;
}
function shouldApplyToWorkspace(pkgPath, updateMap) {
  let content;
  try {
    content = readFileSync4(pkgPath, "utf8");
  } catch {
    return false;
  }
  const pkg = JSON.parse(content);
  const isDepsChanged = shouldApplyToBag(pkg.dependencies, updateMap);
  const isDevDepsChanged = shouldApplyToBag(pkg.devDependencies, updateMap);
  const isPeerChanged = shouldApplyToPeerBag(pkg, updateMap);
  const isChanged = isDepsChanged || isDevDepsChanged || isPeerChanged;
  if (isChanged) {
    writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
`);
  }
  return isChanged;
}
function applyUpdates(cwd, workspaces, updates) {
  const updateMap = new Map(updates.map((u) => [u.name, u]));
  let modified = 0;
  for (const ws of workspaces) {
    const pkgPath = PATH3.resolve(cwd, ws.location, "package.json");
    if (shouldApplyToWorkspace(pkgPath, updateMap)) {
      modified++;
      console.log(chalk5.gray(`  Updated ${ws.name}`));
    }
  }
  return modified;
}

// src/lib/updo/collectWorkspaceDeps.ts
import { readFileSync as readFileSync5 } from "node:fs";
import PATH4 from "node:path";
var DEP_FIELDS = ["dependencies", "devDependencies", "peerDependencies"];
function collectExternalWorkspaceDeps(deps, depField, ws, workspaceNames, declaredDeps) {
  if (!deps) return;
  for (const [name, range] of Object.entries(deps)) {
    if (workspaceNames.has(name)) continue;
    if (range.startsWith("workspace:")) continue;
    declaredDeps.push({
      depType: depField,
      name,
      range,
      workspaceLocation: ws.location,
      workspaceName: ws.name
    });
  }
}
function collectWorkspaceDeps(cwd, workspaces, workspaceNames) {
  const declaredDeps = [];
  for (const ws of workspaces) {
    const pkgPath = PATH4.resolve(cwd, ws.location, "package.json");
    let pkg;
    try {
      pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
    } catch {
      continue;
    }
    for (const depField of DEP_FIELDS) {
      collectExternalWorkspaceDeps(
        pkg[depField],
        depField,
        ws,
        workspaceNames,
        declaredDeps
      );
    }
  }
  return declaredDeps;
}

// src/lib/updo/fetchRegistryInfo.ts
import fs2 from "node:fs";
import os2 from "node:os";
import path2 from "node:path";
import chalk6 from "chalk";
var REGISTRY_BASE = "https://registry.npmjs.org";
var VIEW_FIELDS = ["versions", "dist-tags", "time", "--json"];
function parseNpmrc(filePath, into) {
  let text;
  try {
    text = fs2.readFileSync(filePath, "utf8");
  } catch {
    return;
  }
  for (const rawLine of text.split("\n")) {
    const line = rawLine.trim();
    if (!line || line.startsWith("#") || line.startsWith(";")) continue;
    const tokenMatch = /^\/\/([^:]+?):_authToken=(.+)$/.exec(line);
    if (tokenMatch) {
      const hostPath = tokenMatch[1];
      const token = tokenMatch[2].trim().replaceAll(/^["']|["']$/g, "");
      const host = hostPath.split("/", 1)[0];
      into.tokens.set(`https://${host}`, token);
      continue;
    }
    const scopeMatch = /^(@[^:]+):registry=(.+)$/.exec(line);
    if (scopeMatch) {
      into.scopeRegistries.set(scopeMatch[1], scopeMatch[2].trim().replace(/\/$/, ""));
    }
  }
}
var npmrcConfigCache = { config: void 0 };
function loadNpmrcConfig() {
  if (npmrcConfigCache.config) return npmrcConfigCache.config;
  const config = { scopeRegistries: /* @__PURE__ */ new Map(), tokens: /* @__PURE__ */ new Map() };
  parseNpmrc(path2.join(INIT_CWD(), ".npmrc"), config);
  parseNpmrc(path2.join(os2.homedir(), ".npmrc"), config);
  npmrcConfigCache.config = config;
  return config;
}
function resolveRegistry(packageName2, config) {
  if (packageName2.startsWith("@")) {
    const scope = packageName2.split("/", 1)[0];
    const scoped = config.scopeRegistries.get(scope);
    if (scoped != null && scoped.length > 0) return scoped;
  }
  return REGISTRY_BASE;
}
function combineOutput(stdout, stderr) {
  return [stdout, stderr].filter(Boolean).join("\n").trim();
}
function isRegistryNotFoundOutput(output) {
  return /\bE404\b|\b404\b|not found/i.test(output);
}
function outputSnippet(output) {
  if (!output) return "(no output)";
  return output.length > 1200 ? `${output.slice(0, 1200)}...` : output;
}
function lookupErrorMessage(error) {
  return [
    `Updo: failed to fetch registry metadata for ${error.packageName}.`,
    `Command: ${error.command}`,
    `Exit status: ${error.status ?? "unknown"}`,
    outputSnippet(error.output)
  ].join("\n");
}
function coerceStringRecord(value) {
  const out = {};
  if (value == null || typeof value !== "object" || Array.isArray(value)) return out;
  for (const [key, raw] of Object.entries(value)) {
    if (typeof raw === "string") out[key] = raw;
  }
  return out;
}
function coerceVersions(value) {
  if (Array.isArray(value)) return value.filter((v) => typeof v === "string");
  if (value != null && typeof value === "object") return Object.keys(value);
  return [];
}
function parsePackageViewJson(stdout, options = {}) {
  const data = JSON.parse(stdout);
  const versions = coerceVersions(data.versions);
  const result = {
    distTags: coerceStringRecord(data["dist-tags"] ?? data.distTags),
    versions
  };
  if (options.wantTimes ?? false) {
    const publishTimes = coerceStringRecord(data.time);
    if (Object.keys(publishTimes).length > 0) result.publishTimes = publishTimes;
  }
  return result;
}
function isPackageManagerViewSupported(pm) {
  return pm?.name === "npm" || pm?.name === "pnpm";
}
function packageManagerName(pm) {
  return pm?.name ?? "unknown";
}
function viewCommand(pm, packageName2) {
  return ["view", packageName2, ...VIEW_FIELDS];
}
function appendChunk(current, chunk) {
  return current + (typeof chunk === "string" ? chunk : chunk.toString("utf8"));
}
function runPackageManagerView(pm, args) {
  return new Promise((resolve) => {
    const child = spawn(pm.command, args, {
      cwd: INIT_CWD(),
      env: { FORCE_COLOR: "3", ...process.env },
      stdio: ["ignore", "pipe", "pipe"]
    });
    let stdout = "";
    let stderr = "";
    let isSettled = false;
    child.stdout?.on("data", (chunk) => {
      stdout = appendChunk(stdout, chunk);
    });
    child.stderr?.on("data", (chunk) => {
      stderr = appendChunk(stderr, chunk);
    });
    child.on("error", (error) => {
      if (isSettled) return;
      isSettled = true;
      resolve({
        stderr: [stderr, error.message].filter(Boolean).join("\n"),
        stdout,
        status: null
      });
    });
    child.on("close", (status) => {
      if (isSettled) return;
      isSettled = true;
      resolve({
        stderr,
        status,
        stdout
      });
    });
  });
}
async function fetchRegistryInfoWithPackageManager(packageName2, options) {
  const pm = options.packageManager;
  if (!isPackageManagerViewSupported(pm)) {
    return {
      command: "unknown view",
      output: `Unsupported package manager for command-backed updo lookup: ${packageManagerName(pm)}`,
      packageName: packageName2,
      status: 1,
      type: "fatal"
    };
  }
  const args = viewCommand(pm, packageName2);
  const result = await runPackageManagerView(pm, args);
  const output = combineOutput(result.stdout, result.stderr);
  if (result.status !== 0) {
    return isRegistryNotFoundOutput(output) ? {
      output,
      packageName: packageName2,
      status: result.status,
      type: "not-found"
    } : {
      command: `${pm.command} ${args.join(" ")}`,
      output,
      packageName: packageName2,
      status: result.status,
      type: "fatal"
    };
  }
  try {
    return {
      info: parsePackageViewJson(result.stdout, options),
      packageName: packageName2,
      type: "ok"
    };
  } catch (error) {
    return {
      command: `${pm.command} ${args.join(" ")}`,
      output: error instanceof Error ? `${error.message}
${output}` : output,
      packageName: packageName2,
      status: result.status,
      type: "fatal"
    };
  }
}
async function fetchRegistryInfoDirect(packageName2, options = {}) {
  try {
    const config = loadNpmrcConfig();
    const registry = resolveRegistry(packageName2, config);
    const url = `${registry}/${packageName2}`;
    const headers = {};
    if (!(options.wantTimes ?? false)) {
      headers.Accept = "application/vnd.npm.install-v1+json";
    }
    const token = config.tokens.get(registry);
    if (token != null && token.length > 0) headers.Authorization = `Bearer ${token}`;
    const res = await fetch(url, { headers });
    if (!res.ok) {
      return { distTags: {}, versions: [] };
    }
    const data = await res.json();
    const versionKeys = Object.keys(data.versions ?? {});
    const result = {
      distTags: data["dist-tags"] ?? {},
      versions: versionKeys
    };
    if ((options.wantTimes ?? false) && data.time) {
      const publishTimes = {};
      for (const v of versionKeys) {
        const t = data.time[v];
        if (typeof t === "string") publishTimes[v] = t;
      }
      result.publishTimes = publishTimes;
    }
    return result;
  } catch {
    return { distTags: {}, versions: [] };
  }
}
function runAuthCommand(pm, args, stdio) {
  return spawnSync(pm.command, args, {
    cwd: INIT_CWD(),
    encoding: "utf8",
    env: { FORCE_COLOR: "3", ...process.env },
    stdio
  });
}
function shouldCheckWhoami(pm) {
  const result = runAuthCommand(pm, ["whoami"], "pipe");
  return result.status === 0;
}
function ensureUpdoRegistryAuthenticated(pm) {
  console.log(chalk6.gray(`Updo: checking ${pm.command} authentication after registry 404`));
  if (shouldCheckWhoami(pm)) {
    console.log(chalk6.gray(`Updo: ${pm.command} authentication is active`));
    return;
  }
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
    throw new Error(
      `Updo: ${pm.command} whoami failed and this is not an interactive terminal. Run "${pm.command} login" and retry xy updo.`
    );
  }
  console.warn(chalk6.yellow(`Updo: ${pm.command} whoami failed; starting ${pm.command} login.`));
  const login = runAuthCommand(pm, ["login"], "inherit");
  if (login.status !== 0) {
    throw new Error(`Updo: ${pm.command} login failed. Run "${pm.command} login" manually and retry xy updo.`);
  }
  if (!shouldCheckWhoami(pm)) {
    throw new Error(`Updo: still not authenticated after ${pm.command} login. Run "${pm.command} login" manually and retry xy updo.`);
  }
  console.log(chalk6.gray(`Updo: ${pm.command} authentication is active`));
}
function normalizedConcurrency(value) {
  return Math.max(1, Math.floor(value ?? 16));
}
function logFetchStart(total, concurrency, source) {
  if (total === 0) {
    console.log(chalk6.gray("  No registry metadata to fetch"));
    return;
  }
  console.log(chalk6.gray(`  Fetching metadata for ${total} package(s) via ${source} (${concurrency} concurrent)`));
}
function logFetchComplete(total) {
  if (total > 0) {
    console.log(chalk6.gray(`  Finished registry metadata lookup for ${total} package(s)`));
  }
}
function writeFetchProgress(completed, total) {
  if (completed % 25 === 0 || completed === total) {
    process.stderr.write(`\r  Fetched ${completed}/${total} package metadata records...`);
  }
}
async function fetchAllRegistryInfoDirect(packageNames, options = {}) {
  const results = /* @__PURE__ */ new Map();
  const concurrency = normalizedConcurrency(options.concurrency);
  let completed = 0;
  const total = packageNames.length;
  logFetchStart(total, concurrency, "direct registry fetch");
  await runWithConcurrency(packageNames, concurrency, async (name) => {
    results.set(name, await fetchRegistryInfoDirect(name, { wantTimes: options.wantTimes }));
    completed++;
    writeFetchProgress(completed, total);
  });
  if (total > 0) {
    process.stderr.write("\n");
  }
  logFetchComplete(total);
  return results;
}
async function fetchAllRegistryInfoWithPackageManager(packageNames, options) {
  const pm = options.packageManager;
  if (!isPackageManagerViewSupported(pm)) {
    throw new Error(`Updo: command-backed registry lookup is not supported for ${packageManagerName(pm)}.`);
  }
  const results = /* @__PURE__ */ new Map();
  const notFound = [];
  const concurrency = normalizedConcurrency(options.concurrency);
  let completed = 0;
  const total = packageNames.length;
  logFetchStart(total, concurrency, `${pm.command} view`);
  await runWithConcurrency(packageNames, concurrency, async (name) => {
    const result = await fetchRegistryInfoWithPackageManager(name, options);
    if (result.type === "ok") {
      results.set(name, result.info);
    } else if (result.type === "not-found") {
      notFound.push(result);
    } else {
      throw new Error(lookupErrorMessage(result));
    }
    completed++;
    writeFetchProgress(completed, total);
  });
  if (total > 0) {
    process.stderr.write("\n");
  }
  logFetchComplete(total);
  if (notFound.length === 0) return results;
  console.warn(chalk6.yellow(
    `Updo: ${notFound.length} declared package(s) returned 404 from ${pm.command} view; checking registry authentication.`
  ));
  ensureUpdoRegistryAuthenticated(pm);
  console.log(chalk6.gray(`  Retrying metadata fetch for ${notFound.length} package(s) after authentication`));
  const stillNotFound = [];
  await runWithConcurrency(notFound, concurrency, async (missing) => {
    const result = await fetchRegistryInfoWithPackageManager(missing.packageName, options);
    if (result.type === "ok") {
      results.set(missing.packageName, result.info);
    } else if (result.type === "not-found") {
      stillNotFound.push(missing.packageName);
    } else {
      throw new Error(lookupErrorMessage(result));
    }
  });
  if (stillNotFound.length > 0) {
    throw new Error(
      `Updo: ${pm.command} view still returned 404 for declared package(s) after authentication: ` + stillNotFound.join(", ")
    );
  }
  return results;
}
async function fetchAllRegistryInfo(packageNames, options = {}) {
  if (isPackageManagerViewSupported(options.packageManager)) {
    return await fetchAllRegistryInfoWithPackageManager(packageNames, options);
  }
  return await fetchAllRegistryInfoDirect(packageNames, options);
}

// src/lib/updo/interactiveSelect.ts
import {
  createPrompt,
  ExitPromptError,
  isDownKey,
  isEnterKey,
  isSpaceKey,
  isUpKey,
  useKeypress,
  useRef,
  useState
} from "@inquirer/core";
import chalk7 from "chalk";
var ORANGE = chalk7.hex("#ff8800");
var COLOR = {
  gray: chalk7.gray,
  green: chalk7.green,
  orange: ORANGE,
  red: chalk7.red,
  yellow: chalk7.yellow
};
function classifyCell(prefix, column, hasValue) {
  if (!hasValue) return "gray";
  if (column === "next") return "orange";
  if (column === "downgrade") return "red";
  if (prefix === "^") {
    if (column === "patch" || column === "minor") return "green";
    return "yellow";
  }
  if (prefix === "~") {
    if (column === "patch") return "green";
    if (column === "minor") return "yellow";
    return "red";
  }
  if (column === "patch") return "yellow";
  return "red";
}
function pad(raw, colored, width) {
  return colored + " ".repeat(Math.max(0, width - raw.length));
}
function dot(isSelected) {
  return isSelected ? chalk7.green("\u25CF") : chalk7.dim("\u25CB");
}
function valueOf(dep, column) {
  if (column === "patch") return dep.patch;
  if (column === "minor") return dep.minor;
  if (column === "major") return dep.major;
  if (column === "downgrade") return dep.downgrade;
  return dep.next;
}
function selectionFor(column) {
  if (column === "patch") return 0;
  if (column === "minor") return 1;
  if (column === "major") return 2;
  if (column === "next") return 3;
  return 4;
}
function renderCell(dep, column, selection, width) {
  const value = valueOf(dep, column);
  const raw = value ?? "-";
  const cls = classifyCell(dep.preferredRangePrefix, column, value != null && value.length > 0);
  const colored = COLOR[cls](raw);
  const sel = value != null && value.length > 0 ? dot(selection === selectionFor(column)) : " ";
  return `${sel} ${pad(raw, colored, width)}`;
}
function renderHeader(w, shouldIncludeNext, shouldIncludeDowngrade) {
  const parts = [
    "  ",
    chalk7.bold("Package".padEnd(w.name)),
    chalk7.bold("Current".padEnd(w.current)),
    chalk7.bold("  Patch".padEnd(w.patch + 2)),
    chalk7.bold("  Minor".padEnd(w.minor + 2)),
    chalk7.bold("  Major".padEnd(w.major + 2))
  ];
  if (shouldIncludeNext) parts.push(chalk7.bold("  Next".padEnd(w.next + 2)));
  if (shouldIncludeDowngrade) parts.push(chalk7.bold("  Down".padEnd(w.downgrade + 2)));
  const header = parts.join("  ");
  const totalWidth = w.name + w.current + w.patch + w.minor + w.major + (shouldIncludeNext ? w.next + 2 : 0) + (shouldIncludeDowngrade ? w.downgrade + 2 : 0) + 24;
  return `${header}
${chalk7.gray("\u2500".repeat(totalWidth))}`;
}
function renderRow(dep, selection, isActive, w, shouldIncludeNext, shouldIncludeDowngrade) {
  const pointer = isActive ? chalk7.cyan("\u276F") : " ";
  const rawName = dep.name;
  const name = chalk7[isActive ? "white" : "gray"](rawName);
  const rawCurrent = dep.current;
  const current = chalk7.gray(rawCurrent);
  const patch = renderCell(dep, "patch", selection, w.patch);
  const minor = renderCell(dep, "minor", selection, w.minor);
  const major = renderCell(dep, "major", selection, w.major);
  const next = shouldIncludeNext ? `  ${renderCell(dep, "next", selection, w.next)}` : "";
  const downgrade = shouldIncludeDowngrade ? `  ${renderCell(dep, "downgrade", selection, w.downgrade)}` : "";
  return `${pointer} ${pad(rawName, name, w.name)}  ${pad(rawCurrent, current, w.current)}  ${patch}  ${minor}  ${major}${next}${downgrade}`;
}
function getAvailableSelections(dep) {
  const available = [-1];
  if (dep.patch != null && dep.patch.length > 0) available.push(0);
  if (dep.minor != null && dep.minor.length > 0) available.push(1);
  if (dep.major != null && dep.major.length > 0) available.push(2);
  if (dep.next != null && dep.next.length > 0) available.push(3);
  if (dep.downgrade != null && dep.downgrade.length > 0) available.push(4);
  return available;
}
var RISK_RANK = {
  green: 0,
  yellow: 1,
  red: 2
};
var CLASS_RANK = {
  green: 0,
  yellow: 1,
  red: 2
};
function defaultSelection(dep, options = {}) {
  const candidates = [
    {
      column: "patch",
      selection: 0,
      value: dep.patch
    },
    {
      column: "minor",
      selection: 1,
      value: dep.minor
    },
    {
      column: "major",
      selection: 2,
      value: dep.major
    }
  ];
  const maxRisk = RISK_RANK[options.risk ?? "green"];
  const eligible = candidates.filter((c) => c.value !== void 0).map((c) => {
    const cls = classifyCell(dep.preferredRangePrefix, c.column, true);
    return { ...c, cls: cls === "orange" || cls === "gray" ? "green" : cls };
  }).filter((c) => CLASS_RANK[c.cls] <= maxRisk);
  if (eligible.length === 0) {
    if (dep.downgrade != null && dep.downgrade.length > 0 && maxRisk >= CLASS_RANK.red) return 4;
    return -1;
  }
  if (options.latest ?? false) {
    return eligible.toSorted((a, b) => b.selection - a.selection)[0].selection;
  }
  const sorted = eligible.toSorted((a, b) => {
    if (a.cls !== b.cls) return CLASS_RANK[a.cls] - CLASS_RANK[b.cls];
    return a.selection - b.selection;
  });
  return sorted[0].selection;
}
function getTargetVersion(dep, selection) {
  if (selection === 0) return dep.patch;
  if (selection === 1) return dep.minor;
  if (selection === 2) return dep.major;
  if (selection === 3) return dep.next;
  if (selection === 4) return dep.downgrade;
  return void 0;
}
function computeWidths(rows) {
  let name = 7;
  let current = 7;
  let patch = 5;
  let minor = 5;
  let major = 5;
  let next = 4;
  let downgrade = 4;
  for (const dep of rows) {
    name = Math.max(name, dep.name.length);
    current = Math.max(current, dep.current.length);
    patch = Math.max(patch, (dep.patch ?? "-").length);
    minor = Math.max(minor, (dep.minor ?? "-").length);
    major = Math.max(major, (dep.major ?? "-").length);
    next = Math.max(next, (dep.next ?? "-").length);
    downgrade = Math.max(downgrade, (dep.downgrade ?? "-").length);
  }
  return {
    current,
    downgrade,
    major,
    minor,
    name,
    next,
    patch
  };
}
function renderPage(rows, cursor, selections, w, pageSize, shouldIncludeNext, shouldIncludeDowngrade) {
  const total = rows.length;
  const start = total > pageSize ? Math.max(0, Math.min(cursor - Math.floor(pageSize / 2), total - pageSize)) : 0;
  const end = Math.min(start + pageSize, total);
  const lines = [];
  for (let i = start; i < end; i++) {
    lines.push(renderRow(rows[i], selections[i], i === cursor, w, shouldIncludeNext, shouldIncludeDowngrade));
  }
  if (total > pageSize) {
    if (start > 0) lines.unshift(chalk7.dim("  \u2191 more"));
    if (end < total) lines.push(chalk7.dim("  \u2193 more"));
  }
  return lines.join("\n");
}
var updoPrompt = createPrompt((config, done) => {
  const {
    rows,
    shouldIncludeNext: isIncludeNext,
    latest: isLatest,
    risk
  } = config;
  const [cursor, setCursor] = useState(0);
  const [tick, setTick] = useState(0);
  const availableSelectionsRef = useRef(rows.map((r) => getAvailableSelections(r)));
  const selectionsRef = useRef(rows.map((r) => defaultSelection(r, { latest: isLatest, risk })));
  const widthsRef = useRef(computeWidths(rows));
  useKeypress((key) => {
    if (key.name === "escape" || key.ctrl && key.name === "c") {
      done([]);
      return;
    }
    if (isEnterKey(key)) {
      const results = [];
      for (const [i, dep] of rows.entries()) {
        const version = getTargetVersion(dep, selectionsRef.current[i]);
        if (version != null && version.length > 0) {
          results.push({
            name: dep.name,
            targetRange: version,
            workspaces: dep.workspaces
          });
        }
      }
      done(results);
      return;
    }
    if (isUpKey(key)) {
      setCursor(Math.max(0, cursor - 1));
    } else if (isDownKey(key)) {
      setCursor(Math.min(rows.length - 1, cursor + 1));
    } else if (isSpaceKey(key)) {
      const available = availableSelectionsRef.current[cursor];
      const currentSel = selectionsRef.current[cursor];
      const currentIdx = available.indexOf(currentSel);
      const nextIdx = (currentIdx + 1) % available.length;
      selectionsRef.current[cursor] = available[nextIdx];
      setTick(tick + 1);
    }
  });
  const w = widthsRef.current;
  const isIncludeDowngrade = rows.some((r) => r.downgrade !== void 0);
  const header = renderHeader(w, isIncludeNext, isIncludeDowngrade);
  const page = renderPage(rows, cursor, selectionsRef.current, w, 20, isIncludeNext, isIncludeDowngrade);
  const selectedCount = selectionsRef.current.filter((s) => s >= 0).length;
  const status = chalk7.gray(`  ${selectedCount} isSelected  \u2191/\u2193 navigate  space cycle version  enter confirm`);
  return `${header}
${page}
${status}`;
});
async function interactiveSelect(deps, options = {}) {
  const updatable = deps.filter((d) => d.updateAvailable);
  if (updatable.length === 0) {
    console.log(chalk7.green("\nAll packages are up to date!"));
    return [];
  }
  if (!process.stdout.isTTY) {
    console.log(chalk7.yellow("Non-interactive environment detected, skipping selection."));
    return [];
  }
  try {
    return await updoPrompt({
      shouldIncludeNext: options.shouldIncludeNext ?? false,
      latest: options.latest ?? false,
      risk: options.risk ?? "green",
      rows: updatable
    });
  } catch (error) {
    if (error instanceof ExitPromptError) {
      return [];
    }
    throw error;
  }
}

// src/lib/updo/resolveVersions.ts
import semver2 from "semver";
function parseExclude(pattern) {
  const sep = pattern.indexOf("@", 1);
  if (sep > 0 && sep < pattern.length - 1) {
    const name = pattern.slice(0, sep);
    const version = pattern.slice(sep + 1);
    return { matcher: makeMatcher(name), version };
  }
  return { matcher: makeMatcher(pattern), version: void 0 };
}
function isExcluded(name, version, rules) {
  for (const rule of rules) {
    if (!rule.matcher(name)) continue;
    if (rule.version === void 0) return true;
    if (rule.version === version) return true;
    try {
      if (semver2.satisfies(version, rule.version)) return true;
    } catch {
    }
  }
  return false;
}
function buildExcludeRules(patterns) {
  return patterns.map(parseExclude);
}
function isVersionAllowed(name, version, info, filter, rules) {
  if (isExcluded(name, version, rules)) return true;
  const published = info.publishTimes?.[version];
  if (!(published != null && published.length > 0)) return filter.ignoreMissingTime;
  const publishedMs = Date.parse(published);
  if (Number.isNaN(publishedMs)) return filter.ignoreMissingTime;
  return filter.now - publishedMs >= filter.minutes * 6e4;
}
function filterRegistryInfo(name, info, filter, rules) {
  const allowedVersions = info.versions.filter((v) => isVersionAllowed(name, v, info, filter, rules));
  const allowedSet = new Set(allowedVersions);
  const allowedDistTags = {};
  for (const [tag, version] of Object.entries(info.distTags)) {
    if (allowedSet.has(version)) allowedDistTags[tag] = version;
  }
  return {
    distTags: allowedDistTags,
    publishTimes: info.publishTimes,
    versions: allowedVersions
  };
}
function isDeclaredRangeSatisfiable(declaredRanges, allowedStable) {
  for (const v of allowedStable) {
    for (const range of declaredRanges) {
      try {
        if (semver2.satisfies(v, range)) return true;
      } catch {
      }
    }
  }
  return false;
}
function pickDowngrade(allowedStable, anchor) {
  const below = allowedStable.filter((v) => semver2.lt(v, anchor));
  return highest(below);
}
function pickPrefix(declaredRanges) {
  if (declaredRanges.some((r) => r.startsWith("^"))) return "^";
  if (declaredRanges.some((r) => r.startsWith("~"))) return "~";
  return "";
}
function lowestAnchor(declaredRanges) {
  let lowest;
  for (const range of declaredRanges) {
    try {
      const min = semver2.minVersion(range);
      if (!min) continue;
      if (!lowest || semver2.lt(min, lowest)) lowest = min;
    } catch {
    }
  }
  return lowest;
}
function highest(versions) {
  if (versions.length === 0) return void 0;
  return versions.toSorted(semver2.rcompare)[0];
}
function isStable(version) {
  return semver2.prerelease(version) === null;
}
function format(prefix, version) {
  if (!(version != null && version.length > 0)) return void 0;
  return `${prefix}${version}`;
}
function pickBuckets(stableVersions, anchor) {
  const above = stableVersions.filter((v) => semver2.gt(v, anchor));
  const sameMajor = above.filter((v) => semver2.major(v) === anchor.major);
  const samePatch = sameMajor.filter((v) => semver2.minor(v) === anchor.minor);
  const minorAbove = sameMajor.filter((v) => semver2.minor(v) > anchor.minor);
  const majorAbove = above.filter((v) => semver2.major(v) > anchor.major);
  return {
    major: highest(majorAbove),
    minor: highest(minorAbove),
    patch: highest(samePatch)
  };
}
function pickPrerelease(distTags, anchor) {
  let best;
  for (const tag of ["next", "rc", "beta", "alpha"]) {
    const v = distTags[tag];
    if (!v) continue;
    if (semver2.prerelease(v) === null) continue;
    if (!semver2.gt(v, anchor)) continue;
    if (!(best != null && best.length > 0) || semver2.gt(v, best)) best = v;
  }
  return best;
}
function differentFromCurrent(value, current) {
  if (!(value != null && value.length > 0)) return void 0;
  return value === current ? void 0 : value;
}
function unresolvedDep(name, current, declaredRanges, preferredRangePrefix, workspaces) {
  return {
    current,
    declaredRanges,
    downgrade: void 0,
    major: void 0,
    minor: void 0,
    name,
    next: void 0,
    patch: void 0,
    preferredRangePrefix,
    updateAvailable: false,
    workspaces
  };
}
function normalizedMixedPatch(patch, declaredRanges, preferredRangePrefix, anchor) {
  if (patch != null && patch.length > 0 || declaredRanges.length <= 1) return patch;
  const isAllSameAnchor = declaredRanges.every((range) => {
    const v = semver2.minVersion(range);
    return v !== null && v.version === anchor.version;
  });
  if (!isAllSameAnchor) return patch;
  const normalized = `${preferredRangePrefix}${anchor.version}`;
  return declaredRanges.some((r) => r !== normalized) ? normalized : patch;
}
function resolveOne(name, group, info, options, excludeRules) {
  const nonPeer = group.filter((d) => d.depType !== "peerDependencies");
  const sourceForRange = nonPeer.length > 0 ? nonPeer : group;
  const declaredRanges = [...new Set(sourceForRange.map((d) => d.range))];
  const workspaces = [...new Set(group.map((d) => d.workspaceName))];
  const current = declaredRanges.length === 1 ? declaredRanges[0] : "mixed";
  const preferredRangePrefix = pickPrefix(declaredRanges);
  const anchor = lowestAnchor(declaredRanges);
  if (info === void 0 || anchor === void 0) {
    return unresolvedDep(name, current, declaredRanges, preferredRangePrefix, workspaces);
  }
  const effectiveInfo = options.minReleaseAge ? filterRegistryInfo(name, info, options.minReleaseAge, excludeRules) : info;
  const stable = effectiveInfo.versions.filter((v) => semver2.valid(v) !== null && isStable(v));
  const downgrade = options.minReleaseAge && !isDeclaredRangeSatisfiable(declaredRanges, stable) ? format(preferredRangePrefix, pickDowngrade(stable, anchor)) : void 0;
  const buckets = pickBuckets(stable, anchor);
  const patchRaw = format(preferredRangePrefix, buckets.patch);
  const minorRaw = format(preferredRangePrefix, buckets.minor);
  const majorRaw = format(preferredRangePrefix, buckets.major);
  const nextRaw = options.shouldIncludeNext ?? false ? format(preferredRangePrefix, pickPrerelease(effectiveInfo.distTags, anchor)) : void 0;
  const patch = normalizedMixedPatch(differentFromCurrent(patchRaw, current), declaredRanges, preferredRangePrefix, anchor);
  const minor = differentFromCurrent(minorRaw, current);
  const major = differentFromCurrent(majorRaw, current);
  const next = differentFromCurrent(nextRaw, current);
  const availableVersion = patch ?? minor ?? major ?? next ?? downgrade;
  const isUpdateAvailable = availableVersion !== void 0 && availableVersion.length > 0;
  return {
    current,
    declaredRanges,
    downgrade,
    major,
    minor,
    name,
    next,
    patch,
    preferredRangePrefix,
    updateAvailable: isUpdateAvailable,
    workspaces
  };
}
function resolveVersions(deps, registry, options = {}) {
  const grouped = /* @__PURE__ */ new Map();
  for (const dep of deps) {
    const existing = grouped.get(dep.name);
    if (existing) existing.push(dep);
    else grouped.set(dep.name, [dep]);
  }
  const excludeRules = options.minReleaseAge ? buildExcludeRules(options.minReleaseAge.exclude) : [];
  const resolved = [];
  for (const [name, group] of grouped) {
    resolved.push(resolveOne(name, group, registry.get(name), options, excludeRules));
  }
  return resolved.toSorted((a, b) => {
    if (a.updateAvailable !== b.updateAvailable) return a.updateAvailable ? -1 : 1;
    return a.name.localeCompare(b.name);
  });
}

// src/lib/updo/runUpdo.ts
import { existsSync as existsSync5, readFileSync as readFileSync6 } from "node:fs";
import PATH5 from "node:path";
import chalk8 from "chalk";
function listWorkspacesFromFs(cwd) {
  const workspaces = listDeclaredWorkspaces(cwd);
  const rootPath = PATH5.resolve(cwd, "package.json");
  if (existsSync5(rootPath)) {
    try {
      const root = JSON.parse(readFileSync6(rootPath, "utf8"));
      if (root.name != null && root.name.length > 0 && workspaces.every((ws) => ws.location !== ".")) {
        workspaces.unshift({ location: ".", name: root.name });
      }
    } catch {
    }
  }
  return workspaces;
}
function resolveMinReleaseAgeFilter(pmName, cwd) {
  if (pmName !== "pnpm") return void 0;
  const cfg = readMinReleaseAgeConfig(cwd);
  const minutes = cfg.minutes ?? DEFAULT_MINIMUM_RELEASE_AGE_MINUTES;
  if (minutes <= 0) return void 0;
  const suffix = cfg.minutes === void 0 ? " (default)" : "";
  console.log(chalk8.gray(`  Filtering versions by minimumReleaseAge=${minutes}m${suffix} (pnpm); ${cfg.exclude.length} exclude(s)`));
  return {
    exclude: cfg.exclude,
    ignoreMissingTime: cfg.ignoreMissingTime,
    minutes,
    now: Date.now()
  };
}
async function runUpdo(pm, options = {}) {
  const cwd = INIT_CWD();
  const workspaces = listWorkspacesFromFs(cwd);
  const workspaceNames = new Set(workspaces.map((ws) => ws.name));
  const uniqueDependencyNames = /* @__PURE__ */ new Set();
  console.log(chalk8.gray("Scanning workspace dependencies..."));
  const declaredDeps = collectWorkspaceDeps(cwd, workspaces, workspaceNames);
  for (const dep of declaredDeps) {
    uniqueDependencyNames.add(dep.name);
  }
  console.log(chalk8.gray(`  Found ${uniqueDependencyNames.size} unique dependencies across ${workspaces.length} workspaces`));
  const minReleaseAge = resolveMinReleaseAgeFilter(pm.name, cwd);
  console.log(chalk8.gray("Fetching registry info..."));
  const registryInfo = await fetchAllRegistryInfo([...uniqueDependencyNames], {
    concurrency: options.jobs,
    packageManager: pm,
    wantTimes: minReleaseAge !== void 0
  });
  const isIncludeNext = options.next ?? false;
  const isLatest = options.latest ?? false;
  const risk = options.risk ?? "green";
  const resolved = resolveVersions(declaredDeps, registryInfo, { shouldIncludeNext: isIncludeNext, minReleaseAge });
  const downgradeCount = resolved.filter((r) => r.downgrade !== void 0).length;
  if (downgradeCount > 0) {
    console.log(chalk8.yellow(`  ${downgradeCount} package(s) have a current range that pnpm will reject \u2014 see the red "Down" column for downgrade suggestions.`));
  }
  const updates = await interactiveSelect(resolved, {
    shouldIncludeNext: isIncludeNext,
    latest: isLatest,
    risk
  });
  if (updates.length === 0) {
    console.log(chalk8.gray("No updates selected."));
    return 0;
  }
  console.log(chalk8.gray(`
Applying ${updates.length} updates...`));
  const modified = applyUpdates(cwd, workspaces, updates);
  console.log(chalk8.gray(`  Modified ${modified} package.json files`));
  console.log(chalk8.gray("Installing updated dependencies..."));
  return runSteps("Updo", [
    pm.install(),
    pm.dedupe()
  ], true);
}

// src/actions/updo.ts
var updo = async ({
  jobs,
  latest = false,
  next = false,
  risk = "green"
} = {}) => {
  const pm = getPackageManager();
  return await runUpdo(pm, {
    jobs,
    latest,
    next,
    risk
  });
};
export {
  updo
};
//# sourceMappingURL=updo.mjs.map
