// src/lib/concurrency.ts
import { AsyncLocalStorage } from "async_hooks";
var outputStorage = new AsyncLocalStorage();
var captureInstalled = false;
function installOutputCapture() {
  if (captureInstalled) return;
  captureInstalled = true;
  const originalStdoutWrite = process.stdout.write.bind(process.stdout);
  const originalStderrWrite = process.stderr.write.bind(process.stderr);
  function intercept(original) {
    return function(chunk, ...args) {
      const buffer = outputStorage.getStore();
      if (buffer) {
        buffer.push(typeof chunk === "string" ? chunk : new TextDecoder().decode(chunk));
        return true;
      }
      return original(chunk, ...args);
    };
  }
  process.stdout.write = intercept(originalStdoutWrite);
  process.stderr.write = intercept(originalStderrWrite);
}
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/pm/workspaces.ts
import { existsSync, readFileSync } from "fs";
import PATH from "path";
import { globSync } from "glob";
function readJsonFile(path) {
  if (!existsSync(path)) return void 0;
  try {
    return JSON.parse(readFileSync(path, "utf8"));
  } catch {
    return void 0;
  }
}
function readRootPackageJson(cwd = process.cwd()) {
  return readJsonFile(PATH.resolve(cwd, "package.json"));
}
function detectPackageManagerFromPackageJson(cwd = process.cwd()) {
  const packageManager = readRootPackageJson(cwd)?.packageManager;
  if (!packageManager) return void 0;
  return packageManager.split("@")[0];
}

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

// src/pm/registry.ts
var implementations = /* @__PURE__ */ new Map();
function getPackageManager(name) {
  const pmName = name ?? detectPackageManager();
  const pm = implementations.get(pmName);
  if (!pm) {
    throw new Error(
      `No package manager implementation registered for "${pmName}". Ensure registerPackageManager() has been called before getPackageManager().`
    );
  }
  return pm;
}

// src/lib/fillTemplate.ts
function fillTemplate(template, data) {
  return template.replaceAll(/\{\{(.*?)\}\}/g, (_, key) => data[key.trim()] ?? "");
}

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

// src/lib/generateReadmeFiles.ts
import { execFile } from "child_process";
import FS, { readFileSync as readFileSync2 } from "fs";
import {
  mkdir,
  readFile,
  writeFile
} from "fs/promises";
import { createRequire } from "module";
import PATH2 from "path";
import { createInterface } from "readline";
import { promisify } from "util";
import chalk from "chalk";
var execFileAsync = promisify(execFile);
var require2 = createRequire(import.meta.url);
var packageRoot = PATH2.dirname(require2.resolve("@xylabs/toolchain/package.json"));
var readmeTemplatesDir = PATH2.resolve(packageRoot, "templates", "readme");
function fillReadmeTemplate(template, data) {
  const additionalData = { ...data, safeName: data.name.replaceAll("/", "__").replaceAll("@", "") };
  return fillTemplate(template, additionalData);
}
async function generateTypedoc(packageLocation, entryPoints) {
  const tempDir = PATH2.join(packageLocation, ".temp-typedoc");
  try {
    if (!FS.existsSync(tempDir)) {
      FS.mkdirSync(tempDir, { recursive: true });
    }
    const typedocConfig = {
      disableSources: true,
      entryPointStrategy: "expand",
      entryPoints: entryPoints.map((ep) => PATH2.resolve(packageLocation, ep)),
      excludeExternals: true,
      excludeInternal: true,
      excludePrivate: true,
      githubPages: false,
      hideBreadcrumbs: true,
      hideGenerator: true,
      hidePageTitle: true,
      out: tempDir,
      plugin: ["typedoc-plugin-markdown"],
      readme: "none",
      skipErrorChecking: true,
      sort: ["source-order"],
      theme: "markdown",
      useCodeBlocks: true
    };
    const typedocJsonPath = PATH2.join(tempDir, "typedoc.json");
    FS.writeFileSync(typedocJsonPath, JSON.stringify(typedocConfig, null, 2));
    try {
      await execFileAsync("npx", ["typedoc", "--options", typedocJsonPath], { cwd: process.cwd() });
    } catch {
      return "";
    }
    return consolidateMarkdown(tempDir);
  } catch {
    return "";
  } finally {
    try {
      FS.rmSync(tempDir, { force: true, recursive: true });
    } catch {
    }
  }
}
function consolidateMarkdown(tempDir) {
  let consolidated = "## Reference\n\n";
  const mainReadmePath = PATH2.join(tempDir, "README.md");
  if (FS.existsSync(mainReadmePath)) {
    const mainContent = FS.readFileSync(mainReadmePath, "utf8").replace(/^---(.|\n)*?---\n/, "").replace(/^# .+\n/, "").replaceAll(/\]\((.+?)\.md\)/g, "](#$1)");
    consolidated += mainContent + "\n\n";
  }
  consolidated += processDirectory(tempDir);
  return consolidated.replaceAll(/\n\n\n+/g, "\n\n").replaceAll(/^#### /gm, "### ").replaceAll(/^##### /gm, "#### ").replaceAll(/^###### /gm, "##### ");
}
function processDirectory(dir, level = 0) {
  const indent = "  ".repeat(level);
  let content = "";
  try {
    const items = FS.readdirSync(dir, { withFileTypes: true });
    for (const item of items) {
      if (item.isDirectory()) continue;
      if (item.name === "README.md" || !item.name.endsWith(".md")) continue;
      const fileContent = FS.readFileSync(PATH2.join(dir, item.name), "utf8").replace(/^---(.|\n)*?---\n/, "");
      const moduleName = item.name.replace(".md", "");
      content += `

${indent}### <a id="${moduleName}"></a>${moduleName}

`;
      content += fileContent.replace(/^# .+\n/, "").replaceAll(/\]\((.+?)\.md\)/g, "](#$1)");
    }
    for (const item of items) {
      if (!item.isDirectory()) continue;
      if (item.name === "spec" || item.name.includes(".spec")) continue;
      content += `

${indent}### ${item.name}
`;
      content += processDirectory(PATH2.join(dir, item.name), level + 1);
    }
  } catch {
  }
  return content;
}
function askConfirmation(question) {
  const rl = createInterface({ input: process.stdin, output: process.stdout });
  return new Promise((resolve) => {
    rl.question(question, (answer) => {
      rl.close();
      resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
    });
  });
}
var DEFAULT_README_TEMPLATE = readFileSync2(PATH2.resolve(readmeTemplatesDir, "README.template.md"), "utf8");
var DEFAULT_README_BODY = readFileSync2(PATH2.resolve(readmeTemplatesDir, "README.body.md"), "utf8");
function applyLogoConfig(template, logoUrl, logoLinkUrl) {
  let result = template;
  if (logoUrl) {
    result = result.replace(/\[logo]: .+/, `[logo]: ${logoUrl}`);
    if (logoLinkUrl) {
      result = result.replace(/\[!\[logo]\[]][^)]*\)/, `[![logo][]](${logoLinkUrl})`);
    }
  } else {
    result = result.replace(/\[!\[logo]\[]][^\n]*\n*/, "");
    result = result.replace(/\[logo]: [^\n]*\n?/, "");
  }
  return result;
}
function resolveTemplatePath(templatePath) {
  const cwd = INIT_CWD();
  return templatePath ?? PATH2.join(cwd, ".xy", "README.template.md");
}
async function loadOrCreateTemplate(resolvedTemplatePath) {
  try {
    const template = await readFile(resolvedTemplatePath, "utf8");
    return { created: false, template };
  } catch {
    console.log(chalk.yellow(`Template not found: ${resolvedTemplatePath}`));
    const shouldCreate = await askConfirmation("Would you like to create a stock template? (y/N) ");
    if (!shouldCreate) {
      throw new Error("Template creation declined");
    }
    const template = DEFAULT_README_TEMPLATE;
    await scaffoldTemplate(resolvedTemplatePath, template);
    return { created: true, template };
  }
}
async function scaffoldTemplate(resolvedTemplatePath, template) {
  const xyDir = PATH2.dirname(resolvedTemplatePath);
  await mkdir(xyDir, { recursive: true });
  await writeFile(resolvedTemplatePath, template);
  console.log(chalk.green(`Created template: ${resolvedTemplatePath}`));
  const bodyPath = PATH2.join(xyDir, "README.body.md");
  await writeFile(bodyPath, DEFAULT_README_BODY);
  console.log(chalk.green(`Created body template: ${bodyPath}`));
}
async function resolveBody(location, defaultBody) {
  const localBodyPath = PATH2.join(location, "README.body.md");
  try {
    return await readFile(localBodyPath, "utf8");
  } catch {
    return defaultBody;
  }
}
async function generateReadmeForWorkspace(location, name, template, defaultBody, typedoc, verbose, pm) {
  try {
    const pkgJsonPath = PATH2.join(location, "package.json");
    const pkgJson = JSON.parse(await readFile(pkgJsonPath, "utf8"));
    const body = await resolveBody(location, defaultBody);
    const typedocContent = typedoc ? await generateTypedoc(location, ["src/index*.ts"]) : "";
    const readmeContent = fillReadmeTemplate(template, {
      ...pkgJson,
      body,
      pm,
      typedoc: typedocContent
    });
    await writeFile(PATH2.join(location, "README.md"), readmeContent);
    if (verbose) console.log(chalk.green(`  ${name}`));
    return true;
  } catch (ex) {
    const error = ex;
    console.warn(chalk.yellow(`  Skipped ${location}: ${error.message}`));
    return false;
  }
}
async function loadDefaultBody(resolvedTemplatePath) {
  const xyBodyPath = PATH2.join(PATH2.dirname(resolvedTemplatePath), "README.body.md");
  try {
    return await readFile(xyBodyPath, "utf8");
  } catch {
    return DEFAULT_README_BODY;
  }
}
function flushResults(results) {
  let failed = false;
  for (const { output, success } of results) {
    for (const line of output) {
      process.stdout.write(line);
    }
    if (!success) failed = true;
  }
  return failed;
}
async function generateReadmeFiles({
  jobs,
  logoLinkUrl,
  logoUrl,
  pkg,
  templatePath,
  typedoc = false,
  verbose = false
}) {
  console.log(chalk.green("Generate README Files"));
  const resolvedTemplatePath = resolveTemplatePath(templatePath);
  let template;
  let templateCreated;
  try {
    ({ template, created: templateCreated } = await loadOrCreateTemplate(resolvedTemplatePath));
  } catch {
    return 1;
  }
  template = applyLogoConfig(template, logoUrl, logoLinkUrl);
  if (templateCreated) {
    console.log(chalk.green("Generating README files for all packages..."));
  }
  const defaultBody = await loadDefaultBody(resolvedTemplatePath);
  const pmName = detectPackageManager();
  const pm = getPackageManager();
  const singleWorkspace = pkg && !templateCreated ? pm.findWorkspace(pkg) : void 0;
  const workspaces = singleWorkspace ? [singleWorkspace] : pm.listWorkspaces();
  const concurrency = jobs;
  const results = Array.from({ length: workspaces.length }, () => ({ output: [], success: true }));
  installOutputCapture();
  const start = performance.now();
  await runWithConcurrency(
    workspaces.map((ws, i) => ({ i, ws })),
    concurrency,
    async ({ i, ws }) => {
      const output = [];
      await outputStorage.run(output, async () => {
        const success = await generateReadmeForWorkspace(ws.location, ws.name, template, defaultBody, typedoc, verbose, pmName);
        results[i] = { output, success };
      });
    }
  );
  const failed = flushResults(results);
  const ms = performance.now() - start;
  console.log(chalk.blue(`Generated ${workspaces.length} README(s) in ${ms.toFixed(0)}ms`));
  return failed ? 1 : 0;
}

// src/lib/loadConfig.ts
import chalk2 from "chalk";
import { cosmiconfig } from "cosmiconfig";
import { TypeScriptLoader } from "cosmiconfig-typescript-loader";
import deepmerge from "deepmerge";
var config;
var rootConfigPath;
function createExplorer() {
  return cosmiconfig("xy", { cache: true, loaders: { ".ts": TypeScriptLoader() } });
}
var loadConfig = async (params) => {
  if (config === void 0) {
    const cosmicConfigResult = await createExplorer().search();
    config = cosmicConfigResult?.config ?? {};
    rootConfigPath = cosmicConfigResult?.filepath;
    const configFilePath = cosmicConfigResult?.filepath;
    if (configFilePath !== void 0) {
      console.log(chalk2.green(`Loaded config from ${configFilePath}`));
      if (config.verbose) {
        console.log(chalk2.gray(`${JSON.stringify(config, null, 2)}`));
      }
    }
  }
  return deepmerge(config, params ?? {});
};

// src/actions/readme-gen.ts
async function readmeGen({
  jobs,
  pkg,
  templatePath,
  typedoc,
  verbose
}) {
  const config2 = await loadConfig();
  return await generateReadmeFiles({
    jobs,
    logoLinkUrl: config2.readme?.logoLinkUrl,
    logoUrl: config2.readme?.logoUrl,
    pkg,
    templatePath,
    typedoc,
    verbose
  });
}

// src/actions/readme-init.ts
async function readmeInit({ templatePath }) {
  const config2 = await loadConfig();
  const template = applyLogoConfig(DEFAULT_README_TEMPLATE, config2.readme?.logoUrl, config2.readme?.logoLinkUrl);
  const resolvedTemplatePath = resolveTemplatePath(templatePath);
  await scaffoldTemplate(resolvedTemplatePath, template);
  return 0;
}

// src/actions/readme-lint.ts
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
import PATH3 from "path";
import chalk3 from "chalk";
function lintTemplate(cwd) {
  const result = { errors: [], warnings: [] };
  const templatePath = resolveTemplatePath();
  if (!existsSync3(templatePath)) {
    result.errors.push('Missing .xy/README.template.md (run "xy readme init" to create)');
    return result;
  }
  const template = readFileSync3(templatePath, "utf8");
  if (!template.includes("{{body}}")) {
    result.warnings.push(".xy/README.template.md does not contain a {{body}} placeholder");
  }
  if (!template.includes("{{description}}")) {
    result.warnings.push(".xy/README.template.md does not contain a {{description}} placeholder");
  }
  const bodyPath = PATH3.join(cwd, ".xy", "README.body.md");
  if (!existsSync3(bodyPath)) {
    result.errors.push('Missing .xy/README.body.md (run "xy readme init" to create)');
  }
  return result;
}
function lintLogoConfig(cwd, config2) {
  const result = { errors: [], warnings: [] };
  const templatePath = resolveTemplatePath();
  if (existsSync3(templatePath)) {
    const template = readFileSync3(templatePath, "utf8");
    const logoRef = /\[logo]: (.+)/.exec(template);
    if (logoRef?.[1].includes("example.com")) {
      result.warnings.push(".xy/README.template.md still has the example.com logo placeholder \u2014 update it or set readme.logoUrl in xy.config.ts");
    } else if (!logoRef && !config2.readme?.logoUrl) {
      result.warnings.push("No logo URL configured in xy.config.ts (readme.logoUrl) or template");
    }
  }
  if (!config2.readme?.logoUrl && !config2.readme?.logoLinkUrl) {
    result.warnings.push("No readme.logoUrl or readme.logoLinkUrl configured in xy.config.ts");
  }
  return result;
}
function lintPackages(cwd) {
  const result = { errors: [], warnings: [] };
  const pm = getPackageManager();
  const workspaces = pm.listWorkspaces();
  for (const { location, name } of workspaces) {
    if (location === ".") continue;
    const pkgPath = PATH3.join(cwd, location, "package.json");
    try {
      const pkg = JSON.parse(readFileSync3(pkgPath, "utf8"));
      if (pkg.private) continue;
      if (!pkg.description) {
        result.warnings.push(`${name} is missing a "description" in package.json`);
      }
      const readmePath = PATH3.join(cwd, location, "README.md");
      if (!existsSync3(readmePath)) {
        result.errors.push(`${name} is missing README.md`);
      }
    } catch {
    }
  }
  return result;
}
function readmeLint({ config: config2, verbose }) {
  const cwd = INIT_CWD();
  console.log(chalk3.green("Readme Lint"));
  const checks = [
    lintTemplate(cwd),
    lintLogoConfig(cwd, config2),
    lintPackages(cwd)
  ];
  let errorCount = 0;
  let warningCount = 0;
  for (const { errors, warnings } of checks) {
    for (const error of errors) {
      console.log(chalk3.red(`  \u2717 ${error}`));
      errorCount++;
    }
    for (const warning of warnings) {
      console.log(chalk3.yellow(`  \u26A0 ${warning}`));
      warningCount++;
    }
  }
  if (errorCount === 0 && warningCount === 0) {
    console.log(chalk3.green("  All checks passed"));
  } else {
    if (verbose) {
      console.log(chalk3.gray(`  ${errorCount} error(s), ${warningCount} warning(s)`));
    }
  }
  return errorCount > 0 ? 1 : 0;
}

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

// src/xy/common/readme/genCommand.ts
var genCommand = {
  builder: (yargs) => {
    return packagePositionalParam(yargs).option("template", {
      alias: "t",
      description: "Path to README.template.md",
      type: "string"
    }).option("notypedoc", {
      default: false,
      description: "Disable TypeDoc reference sections",
      type: "boolean"
    });
  },
  aliases: ["$0"],
  command: "gen [package]",
  describe: "Generate README.md files from template",
  handler: async (argv) => {
    if (argv.verbose) console.log("Readme Gen");
    process.exitCode = await readmeGen({
      jobs: argv.jobs,
      pkg: argv.package,
      templatePath: argv.template,
      typedoc: !argv.notypedoc,
      verbose: !!argv.verbose
    });
  }
};

// src/xy/common/readme/initCommand.ts
var initCommand = {
  builder: (yargs) => {
    return yargs.option("template", {
      alias: "t",
      description: "Path to README.template.md",
      type: "string"
    });
  },
  command: "init",
  describe: "Initialize README template and logo files",
  handler: async (argv) => {
    if (argv.verbose) console.log("Readme Init");
    process.exitCode = await readmeInit({
      templatePath: argv.template,
      verbose: !!argv.verbose
    });
  }
};

// src/xy/common/readme/lintCommand.ts
var lintCommand = {
  command: "lint",
  describe: "Check for missing readme templates, body files, logos, and descriptions",
  handler: async (argv) => {
    const config2 = await loadConfig();
    process.exitCode = readmeLint({ config: config2, verbose: !!argv.verbose });
  }
};

// src/xy/common/readme/index.ts
var readmeCommand = {
  builder: (yargs) => {
    return yargs.command(genCommand).command(initCommand).command(lintCommand).demandCommand(1, "Please specify a readme subcommand").strictCommands();
  },
  command: "readme",
  describe: "Readme - README file utilities",
  handler: () => {
  }
};
export {
  readmeCommand
};
//# sourceMappingURL=index.mjs.map