import CJS_COMPAT_NODE_URL_fkaa0x0zihe from 'node:url';
import CJS_COMPAT_NODE_PATH_fkaa0x0zihe from 'node:path';
import CJS_COMPAT_NODE_MODULE_fkaa0x0zihe from "node:module";

var __filename = CJS_COMPAT_NODE_URL_fkaa0x0zihe.fileURLToPath(import.meta.url);
var __dirname = CJS_COMPAT_NODE_PATH_fkaa0x0zihe.dirname(__filename);
var require = CJS_COMPAT_NODE_MODULE_fkaa0x0zihe.createRequire(import.meta.url);

// ------------------------------------------------------------
// end of CJS compatibility banner, injected by Storybook's esbuild configuration
// ------------------------------------------------------------
import {
  invariant
} from "./chunk-7SIASK4H.js";
import {
  resolvePackageDir
} from "./chunk-IZCZHPXK.js";
import {
  any,
  require_prompts,
  up2 as up
} from "./chunk-UL5XA4RJ.js";
import {
  require_picocolors
} from "./chunk-Q4KEXWTH.js";
import {
  __toESM
} from "./chunk-4ILNNMLG.js";

// src/cli/project_types.ts
import { minVersion, validRange } from "semver";
function eqMajor(versionRange, major) {
  return validRange(versionRange) ? minVersion(versionRange)?.major === major : !1;
}
var externalFrameworks = [
  { name: "qwik", packageName: "storybook-framework-qwik" },
  {
    name: "solid",
    packageName: "storybook-solidjs-vite",
    frameworks: ["storybook-solidjs-vite"],
    renderer: "storybook-solidjs-vite"
  },
  {
    name: "nuxt",
    packageName: "@storybook-vue/nuxt",
    frameworks: ["@storybook-vue/nuxt"],
    renderer: "@storybook/vue3"
  }
], SUPPORTED_RENDERERS = [
  "react",
  "react-native",
  "vue3",
  "angular",
  "ember",
  "preact",
  "svelte",
  "qwik",
  "solid"
], ProjectType = /* @__PURE__ */ ((ProjectType2) => (ProjectType2.UNDETECTED = "UNDETECTED", ProjectType2.UNSUPPORTED = "UNSUPPORTED", ProjectType2.REACT = "REACT", ProjectType2.REACT_SCRIPTS = "REACT_SCRIPTS", ProjectType2.REACT_NATIVE = "REACT_NATIVE", ProjectType2.REACT_NATIVE_WEB = "REACT_NATIVE_WEB", ProjectType2.REACT_NATIVE_AND_RNW = "REACT_NATIVE_AND_RNW", ProjectType2.REACT_PROJECT = "REACT_PROJECT", ProjectType2.WEBPACK_REACT = "WEBPACK_REACT", ProjectType2.NEXTJS = "NEXTJS", ProjectType2.VUE3 = "VUE3", ProjectType2.NUXT = "NUXT", ProjectType2.ANGULAR = "ANGULAR", ProjectType2.EMBER = "EMBER", ProjectType2.WEB_COMPONENTS = "WEB_COMPONENTS", ProjectType2.HTML = "HTML", ProjectType2.QWIK = "QWIK", ProjectType2.PREACT = "PREACT", ProjectType2.SVELTE = "SVELTE", ProjectType2.SVELTEKIT = "SVELTEKIT", ProjectType2.SERVER = "SERVER", ProjectType2.NX = "NX", ProjectType2.SOLID = "SOLID", ProjectType2))(ProjectType || {}), CoreBuilder = /* @__PURE__ */ ((CoreBuilder2) => (CoreBuilder2.Webpack5 = "webpack5", CoreBuilder2.Vite = "vite", CoreBuilder2))(CoreBuilder || {}), CoreWebpackCompilers = /* @__PURE__ */ ((CoreWebpackCompilers2) => (CoreWebpackCompilers2.Babel = "babel", CoreWebpackCompilers2.SWC = "swc", CoreWebpackCompilers2))(CoreWebpackCompilers || {}), CommunityBuilder = /* @__PURE__ */ ((CommunityBuilder2) => (CommunityBuilder2.Rsbuild = "rsbuild", CommunityBuilder2))(CommunityBuilder || {}), compilerNameToCoreCompiler = {
  "@storybook/addon-webpack5-compiler-babel": "babel" /* Babel */,
  "@storybook/addon-webpack5-compiler-swc": "swc" /* SWC */
}, builderNameToCoreBuilder = {
  "@storybook/builder-webpack5": "webpack5" /* Webpack5 */,
  "@storybook/builder-vite": "vite" /* Vite */
}, SupportedLanguage = /* @__PURE__ */ ((SupportedLanguage2) => (SupportedLanguage2.JAVASCRIPT = "javascript", SupportedLanguage2.TYPESCRIPT = "typescript", SupportedLanguage2))(SupportedLanguage || {}), supportedTemplates = [
  {
    preset: "NUXT" /* NUXT */,
    dependencies: ["nuxt"],
    matcherFunction: ({ dependencies }) => dependencies?.every(Boolean) ?? !0
  },
  {
    preset: "VUE3" /* VUE3 */,
    dependencies: {
      // This Vue template works with Vue 3
      vue: (versionRange) => versionRange === "next" || eqMajor(versionRange, 3)
    },
    matcherFunction: ({ dependencies }) => dependencies?.some(Boolean) ?? !1
  },
  {
    preset: "EMBER" /* EMBER */,
    dependencies: ["ember-cli"],
    matcherFunction: ({ dependencies }) => dependencies?.every(Boolean) ?? !0
  },
  {
    preset: "NEXTJS" /* NEXTJS */,
    dependencies: ["next"],
    matcherFunction: ({ dependencies }) => dependencies?.every(Boolean) ?? !0
  },
  {
    preset: "QWIK" /* QWIK */,
    dependencies: ["@builder.io/qwik"],
    matcherFunction: ({ dependencies }) => dependencies?.every(Boolean) ?? !0
  },
  {
    preset: "REACT_PROJECT" /* REACT_PROJECT */,
    peerDependencies: ["react"],
    matcherFunction: ({ peerDependencies }) => peerDependencies?.every(Boolean) ?? !0
  },
  {
    preset: "REACT_NATIVE" /* REACT_NATIVE */,
    dependencies: ["react-native", "react-native-scripts"],
    matcherFunction: ({ dependencies }) => dependencies?.some(Boolean) ?? !1
  },
  {
    preset: "REACT_SCRIPTS" /* REACT_SCRIPTS */,
    // For projects using a custom/forked `react-scripts` package.
    files: ["/node_modules/.bin/react-scripts"],
    // For standard CRA projects
    dependencies: ["react-scripts"],
    matcherFunction: ({ dependencies, files }) => (dependencies?.every(Boolean) || files?.every(Boolean)) ?? !1
  },
  {
    preset: "ANGULAR" /* ANGULAR */,
    dependencies: ["@angular/core"],
    matcherFunction: ({ dependencies }) => dependencies?.every(Boolean) ?? !0
  },
  {
    preset: "WEB_COMPONENTS" /* WEB_COMPONENTS */,
    dependencies: ["lit-element", "lit-html", "lit"],
    matcherFunction: ({ dependencies }) => dependencies?.some(Boolean) ?? !1
  },
  {
    preset: "PREACT" /* PREACT */,
    dependencies: ["preact"],
    matcherFunction: ({ dependencies }) => dependencies?.every(Boolean) ?? !0
  },
  {
    // TODO: This only works because it is before the SVELTE template. could be more explicit
    preset: "SVELTEKIT" /* SVELTEKIT */,
    dependencies: ["@sveltejs/kit"],
    matcherFunction: ({ dependencies }) => dependencies?.every(Boolean) ?? !0
  },
  {
    preset: "SVELTE" /* SVELTE */,
    dependencies: ["svelte"],
    matcherFunction: ({ dependencies }) => dependencies?.every(Boolean) ?? !0
  },
  {
    preset: "SOLID" /* SOLID */,
    dependencies: ["solid-js"],
    matcherFunction: ({ dependencies }) => dependencies?.every(Boolean) ?? !0
  },
  // DO NOT MOVE ANY TEMPLATES BELOW THIS LINE
  // React is part of every Template, after Storybook is initialized once
  {
    preset: "WEBPACK_REACT" /* WEBPACK_REACT */,
    dependencies: ["react", "webpack"],
    matcherFunction: ({ dependencies }) => dependencies?.every(Boolean) ?? !0
  },
  {
    preset: "REACT" /* REACT */,
    dependencies: ["react"],
    matcherFunction: ({ dependencies }) => dependencies?.every(Boolean) ?? !0
  }
], unsupportedTemplate = {
  preset: "UNSUPPORTED" /* UNSUPPORTED */,
  dependencies: {},
  matcherFunction: ({ dependencies }) => dependencies?.some(Boolean) ?? !1
}, notInstallableProjectTypes = [
  "UNDETECTED" /* UNDETECTED */,
  "UNSUPPORTED" /* UNSUPPORTED */,
  "NX" /* NX */
], installableProjectTypes = Object.values(ProjectType).filter((type) => !notInstallableProjectTypes.includes(type)).map((type) => type.toLowerCase());

// src/cli/dirs.ts
import { join as join2 } from "node:path";
import { Readable as Readable2 } from "node:stream";
import { pipeline as pipeline2 } from "node:stream/promises";
import { createGunzip } from "node:zlib";
import { temporaryDirectory, versions } from "storybook/internal/common";

// ../node_modules/get-npm-tarball-url/lib/index.mjs
function src_default(pkgName, pkgVersion, opts) {
  let registry;
  opts?.registry ? registry = opts.registry.endsWith("/") ? opts.registry : `${opts.registry}/` : registry = "https://registry.npmjs.org/";
  let scopelessName = getScopelessName(pkgName);
  return `${registry}${pkgName}/-/${scopelessName}-${removeBuildMetadataFromVersion(pkgVersion)}.tgz`;
}
function removeBuildMetadataFromVersion(version) {
  let plusPos = version.indexOf("+");
  return plusPos === -1 ? version : version.substring(0, plusPos);
}
function getScopelessName(name) {
  return name[0] !== "@" ? name : name.split("/")[1];
}

// ../node_modules/modern-tar/dist/unpacker-BKKRRs7i.js
var FLAGTYPE = {
  0: "file",
  1: "link",
  2: "symlink",
  3: "character-device",
  4: "block-device",
  5: "directory",
  6: "fifo",
  x: "pax-header",
  g: "pax-global-header",
  L: "gnu-long-name",
  K: "gnu-long-link-name"
}, ZERO_BLOCK = new Uint8Array(512), encoder = new TextEncoder(), decoder = new TextDecoder();
function readString(view, offset, size) {
  let end = view.indexOf(0, offset), sliceEnd = end === -1 || end > offset + size ? offset + size : end;
  return decoder.decode(view.subarray(offset, sliceEnd));
}
function readOctal(view, offset, size) {
  let value = 0, end = offset + size;
  for (let i = offset; i < end; i++) {
    let charCode = view[i];
    if (charCode === 0) break;
    charCode !== 32 && (value = (value << 3) + (charCode - 48));
  }
  return value;
}
function readNumeric(view, offset, size) {
  if (view[offset] & 128) {
    let result = 0;
    result = view[offset] & 127;
    for (let i = 1; i < size; i++) result = result * 256 + view[offset + i];
    if (!Number.isSafeInteger(result)) throw new Error("TAR number too large");
    return result;
  }
  return readOctal(view, offset, size);
}
var CHECKSUM_SPACE = 32;
function validateChecksum(block) {
  let stored = readOctal(block, 148, 8), sum = 0;
  for (let i = 0; i < block.length; i++) i >= 148 && i < 156 ? sum += CHECKSUM_SPACE : sum += block[i];
  return stored === sum;
}
function parseUstarHeader(block, strict) {
  if (strict && !validateChecksum(block)) throw new Error("Invalid tar header checksum.");
  let typeflag = readString(block, 156, 1), header = {
    name: readString(block, 0, 100),
    mode: readOctal(block, 100, 8),
    uid: readNumeric(block, 108, 8),
    gid: readNumeric(block, 116, 8),
    size: readNumeric(block, 124, 12),
    mtime: new Date(readNumeric(block, 136, 12) * 1e3),
    type: FLAGTYPE[typeflag] || "file",
    linkname: readString(block, 157, 100)
  }, magic = readString(block, 257, 6);
  return magic.trim() === "ustar" && (header.uname = readString(block, 265, 32), header.gname = readString(block, 297, 32)), magic === "ustar" && (header.prefix = readString(block, 345, 155)), header;
}
var PAX_MAPPING = {
  path: ["name", (v) => v],
  linkpath: ["linkname", (v) => v],
  size: ["size", (v) => parseInt(v, 10)],
  mtime: ["mtime", parseFloat],
  uid: ["uid", (v) => parseInt(v, 10)],
  gid: ["gid", (v) => parseInt(v, 10)],
  uname: ["uname", (v) => v],
  gname: ["gname", (v) => v]
};
function parsePax(buffer) {
  let decoder$1 = new TextDecoder("utf-8"), overrides = {}, pax = {}, offset = 0;
  for (; offset < buffer.length; ) {
    let spaceIndex = buffer.indexOf(32, offset);
    if (spaceIndex === -1) break;
    let length = parseInt(decoder$1.decode(buffer.subarray(offset, spaceIndex)), 10);
    if (Number.isNaN(length) || length === 0) break;
    let recordEnd = offset + length, [key, value] = decoder$1.decode(buffer.subarray(spaceIndex + 1, recordEnd - 1)).split("=", 2);
    if (key && value !== void 0) {
      pax[key] = value;
      let mapping = PAX_MAPPING[key];
      if (mapping) {
        let [targetKey, parser] = mapping, parsedValue = parser(value);
        (typeof parsedValue == "string" || !Number.isNaN(parsedValue)) && (overrides[targetKey] = parsedValue);
      }
    }
    offset = recordEnd;
  }
  return Object.keys(pax).length > 0 && (overrides.pax = pax), overrides;
}
function applyOverrides(header, overrides) {
  overrides.name !== void 0 && (header.name = overrides.name), overrides.linkname !== void 0 && (header.linkname = overrides.linkname), overrides.size !== void 0 && (header.size = overrides.size), overrides.mtime !== void 0 && (header.mtime = new Date(overrides.mtime * 1e3)), overrides.uid !== void 0 && (header.uid = overrides.uid), overrides.gid !== void 0 && (header.gid = overrides.gid), overrides.uname !== void 0 && (header.uname = overrides.uname), overrides.gname !== void 0 && (header.gname = overrides.gname), overrides.pax && (header.pax = Object.assign({}, header.pax ?? {}, overrides.pax));
}
function getMetaParser(type) {
  switch (type) {
    case "pax-global-header":
    case "pax-header":
      return parsePax;
    case "gnu-long-name":
      return (data) => ({ name: readString(data, 0, data.length) });
    case "gnu-long-link-name":
      return (data) => ({ linkname: readString(data, 0, data.length) });
    default:
      return;
  }
}
var EOF_BUFFER = new Uint8Array(512 * 2);
function transformHeader(header, options) {
  let { strip, filter, map } = options;
  if (!strip && !filter && !map) return header;
  let h = { ...header };
  if (strip && strip > 0) {
    let components = h.name.split("/").filter(Boolean);
    if (strip >= components.length) return null;
    let newName = components.slice(strip).join("/");
    if (h.name = h.type === "directory" && !newName.endsWith("/") ? `${newName}/` : newName, h.linkname?.startsWith("/")) {
      let linkComponents = h.linkname.split("/").filter(Boolean);
      h.linkname = strip >= linkComponents.length ? "/" : `/${linkComponents.slice(strip).join("/")}`;
    }
  }
  if (filter?.(h) === !1) return null;
  let result = map ? map(h) : h;
  return result && (!result.name || !result.name.trim() || result.name === "." || result.name === "/") ? null : result;
}
var STATE_HEADER = 0, STATE_BODY = 1, STATE_PADDING = 2, STATE_AWAIT_EOF = 3;
function createTarUnpacker(handler, options = {}) {
  let strict = options.strict ?? !1, chunkQueue = [], totalAvailable = 0, state = STATE_HEADER, waitingForData = !1, currentEntry = null, paxGlobals = {}, nextEntryOverrides = {};
  function consume(size, callback) {
    let remaining = Math.min(size, totalAvailable), initialRemaining = remaining;
    for (; remaining > 0 && chunkQueue.length > 0; ) {
      let chunkNode = chunkQueue[0], available = chunkNode.data.length - chunkNode.consumed, toProcess = Math.min(remaining, available);
      callback && callback(chunkNode.data.subarray(chunkNode.consumed, chunkNode.consumed + toProcess)), chunkNode.consumed += toProcess, remaining -= toProcess, chunkNode.consumed >= chunkNode.data.length && chunkQueue.shift();
    }
    return totalAvailable -= initialRemaining - remaining, initialRemaining - remaining;
  }
  function read(size) {
    let toRead = Math.min(size, totalAvailable);
    if (toRead === 0) return null;
    let chunk = chunkQueue[0];
    if (chunk && chunk.data.length - chunk.consumed >= toRead) {
      let result$1 = chunk.data.subarray(chunk.consumed, chunk.consumed + toRead);
      return chunk.consumed += toRead, totalAvailable -= toRead, chunk.consumed >= chunk.data.length && chunkQueue.shift(), result$1;
    }
    let result = new Uint8Array(toRead), offset = 0;
    return consume(toRead, (data) => {
      result.set(data, offset), offset += data.length;
    }), result;
  }
  function process2() {
    for (; ; ) switch (state) {
      case STATE_HEADER: {
        if (totalAvailable < 512) {
          waitingForData = !0;
          return;
        }
        let headerBlock = read(512);
        if (!headerBlock) {
          waitingForData = !0;
          return;
        }
        if (isZeroBlock(headerBlock)) {
          state = STATE_AWAIT_EOF;
          continue;
        }
        waitingForData = !1;
        try {
          let internalHeader = parseUstarHeader(headerBlock, strict), header = {
            ...internalHeader,
            name: internalHeader.name
          }, metaParser = getMetaParser(header.type);
          if (metaParser) {
            let paddedSize = header.size + 511 & -512;
            if (totalAvailable < paddedSize) {
              waitingForData = !0, chunkQueue.unshift({
                data: headerBlock,
                consumed: 0
              }), totalAvailable += 512;
              return;
            }
            let metaBlock = read(paddedSize);
            if (!metaBlock) {
              waitingForData = !0;
              return;
            }
            let overrides = metaParser(metaBlock.subarray(0, header.size));
            header.type === "pax-global-header" ? Object.assign(paxGlobals, overrides) : Object.assign(nextEntryOverrides, overrides);
            continue;
          }
          internalHeader.prefix && (header.name = `${internalHeader.prefix}/${header.name}`), applyOverrides(header, paxGlobals), applyOverrides(header, nextEntryOverrides), nextEntryOverrides = {}, handler.onHeader(header), header.size > 0 ? (currentEntry = {
            remaining: header.size,
            padding: -header.size & 511
          }, state = STATE_BODY) : handler.onEndEntry();
        } catch (error) {
          handler.onError(error);
          return;
        }
        continue;
      }
      case STATE_BODY: {
        if (!currentEntry) throw new Error("No current entry for body");
        let toForward = Math.min(currentEntry.remaining, totalAvailable);
        if (toForward > 0) {
          let consumed = consume(toForward, handler.onData);
          currentEntry.remaining -= consumed;
        }
        if (currentEntry.remaining === 0)
          state = currentEntry.padding > 0 ? STATE_PADDING : STATE_HEADER, state === STATE_HEADER && (handler.onEndEntry(), currentEntry = null);
        else if (totalAvailable === 0) {
          waitingForData = !0;
          return;
        }
        continue;
      }
      case STATE_PADDING:
        if (!currentEntry) throw new Error("No current entry for padding");
        if (totalAvailable < currentEntry.padding) {
          waitingForData = !0;
          return;
        }
        currentEntry.padding > 0 && consume(currentEntry.padding), handler.onEndEntry(), currentEntry = null, state = STATE_HEADER;
        continue;
      case STATE_AWAIT_EOF: {
        if (totalAvailable < 512) {
          waitingForData = !0;
          return;
        }
        let secondBlock = read(512);
        if (!secondBlock) {
          waitingForData = !0;
          return;
        }
        if (isZeroBlock(secondBlock)) return;
        if (strict) {
          handler.onError(new Error("Invalid EOF"));
          return;
        }
        chunkQueue.unshift({
          data: secondBlock,
          consumed: 0
        }), totalAvailable += 512, state = STATE_HEADER;
        continue;
      }
      default:
        throw new Error("Invalid state in tar unpacker.");
    }
  }
  return {
    write(chunk) {
      if (chunk.length !== 0 && (chunkQueue.push({
        data: chunk,
        consumed: 0
      }), totalAvailable += chunk.length, waitingForData)) {
        waitingForData = !1;
        try {
          process2();
        } catch (error) {
          handler.onError(error);
        }
      }
    },
    end() {
      try {
        if (waitingForData || process2(), strict) {
          if (currentEntry && currentEntry.remaining > 0) {
            let error = new Error("Tar archive is truncated.");
            throw handler.onError(error), error;
          }
          if (totalAvailable > 0 && read(totalAvailable)?.some((b) => b !== 0)) {
            let error = new Error("Invalid EOF.");
            throw handler.onError(error), error;
          }
          if (waitingForData) {
            let error = new Error("Tar archive is truncated.");
            throw handler.onError(error), error;
          }
        } else currentEntry && (handler.onEndEntry(), currentEntry = null);
      } catch (error) {
        handler.onError(error);
      }
    }
  };
}
function isZeroBlock(block) {
  if (block.byteOffset % 8 === 0) {
    let view = new BigUint64Array(block.buffer, block.byteOffset, block.length / 8);
    for (let i = 0; i < view.length; i++) if (view[i] !== 0n) return !1;
    return !0;
  }
  for (let i = 0; i < block.length; i++) if (block[i] !== 0) return !1;
  return !0;
}

// ../node_modules/modern-tar/dist/fs/index.js
import * as fs from "node:fs/promises";
import { cpus } from "node:os";
import * as path from "node:path";
import { PassThrough, Readable, Writable } from "node:stream";
import { createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";
var unicodeCache = /* @__PURE__ */ new Map(), normalizeUnicode = (s) => {
  let result = unicodeCache.get(s);
  return result !== void 0 && unicodeCache.delete(s), result = result ?? s.normalize("NFD"), unicodeCache.set(s, result), unicodeCache.size > 1e4 && unicodeCache.delete(unicodeCache.keys().next().value), result;
};
function validateBounds(targetPath, destDir, errorMessage) {
  let target = normalizeUnicode(path.resolve(targetPath)), dest = path.resolve(destDir);
  if (target !== dest && !target.startsWith(dest + path.sep)) throw new Error(errorMessage);
}
var win32Reserved = {
  ":": "\uF03A",
  "<": "\uF03C",
  ">": "\uF03E",
  "|": "\uF07C",
  "?": "\uF03F",
  "*": "\uF02A",
  '"': "\uF022"
};
function normalizeName(name) {
  let path$1 = name.replace(/\\/g, "/");
  if (path$1.split("/").includes("..") || /^[a-zA-Z]:\.\./.test(path$1)) throw new Error(`${name} points outside extraction directory`);
  let relative = path$1;
  return /^[a-zA-Z]:/.test(relative) ? relative = relative.replace(/^[a-zA-Z]:[/\\]?/, "") : relative.startsWith("/") && (relative = relative.replace(/^\/+/, "")), process.platform === "win32" ? relative.replace(/[<>:"|?*]/g, (char) => win32Reserved[char]) : relative;
}
var normalizeHeaderName = (s) => normalizeUnicode(normalizeName(s.replace(/\/+$/, "")));
function unpackTar(directoryPath, options = {}) {
  let { streamTimeout = 5e3, ...fsOptions } = options, timeoutId = null, { handler, signal } = createFSHandler(directoryPath, fsOptions), unpacker = createTarUnpacker(handler, fsOptions), stream;
  function resetTimeout() {
    timeoutId && clearTimeout(timeoutId), streamTimeout !== 1 / 0 && streamTimeout > 0 && (timeoutId = setTimeout(() => {
      let err = new Error(`Stream timed out after ${streamTimeout}ms of inactivity.`);
      stream.destroy(err);
    }, streamTimeout));
  }
  return stream = new Writable({
    write(chunk, _, callback) {
      if (resetTimeout(), signal.aborted) return callback(signal.reason);
      try {
        unpacker.write(chunk), callback();
      } catch (writeErr) {
        callback(writeErr);
      }
    },
    async final(callback) {
      timeoutId && clearTimeout(timeoutId);
      try {
        if (signal.aborted) return callback(signal.reason);
        unpacker.end(), await handler.process(), callback();
      } catch (finalErr) {
        callback(finalErr);
      }
    }
  }), stream.on("close", () => {
    timeoutId && clearTimeout(timeoutId);
  }), resetTimeout(), stream;
}
function createFSHandler(directoryPath, options) {
  let { maxDepth = 1024, dmode, fmode, concurrency = cpus().length || 8 } = options, abortController = new AbortController(), { signal } = abortController, opQueue = [], activeOps = 0, pathPromises = /* @__PURE__ */ new Map(), activeEntryStream = null, processingEnded = !1, resolveDrain, drainPromise = new Promise((resolve4) => {
    resolveDrain = resolve4;
  }), processQueue = () => {
    for (signal.aborted && (opQueue.length = 0); activeOps < concurrency && opQueue.length > 0; ) {
      activeOps++;
      let op = opQueue.shift();
      if (!op) break;
      op();
    }
    processingEnded && activeOps === 0 && opQueue.length === 0 && resolveDrain();
  }, destDirPromise = (async () => {
    let symbolic = normalizeUnicode(path.resolve(directoryPath));
    await fs.mkdir(symbolic, { recursive: !0 });
    try {
      let real = await fs.realpath(symbolic);
      return {
        symbolic,
        real
      };
    } catch (err) {
      throw signal.aborted ? signal.reason : err;
    }
  })();
  destDirPromise.catch((err) => {
    signal.aborted || abortController.abort(err);
  });
  let ensureDirectoryExists = (dirPath) => {
    let promise = pathPromises.get(dirPath);
    return promise || (promise = (async () => {
      if (signal.aborted) throw signal.reason;
      let destDir = await destDirPromise;
      if (dirPath === destDir.symbolic) return "directory";
      if (await ensureDirectoryExists(path.dirname(dirPath)), signal.aborted) throw signal.reason;
      try {
        let stat2 = await fs.lstat(dirPath);
        if (stat2.isDirectory()) return "directory";
        if (stat2.isSymbolicLink()) {
          let realPath = await fs.realpath(dirPath);
          if (validateBounds(realPath, destDir.real, `Symlink "${dirPath}" points outside the extraction directory.`), (await fs.stat(realPath)).isDirectory()) return "directory";
        }
        throw new Error(`"${dirPath}" is not a valid directory component.`);
      } catch (err) {
        if (err.code === "ENOENT")
          return await fs.mkdir(dirPath, { mode: dmode }), "directory";
        throw err;
      }
    })(), pathPromises.set(dirPath, promise), promise);
  };
  return {
    handler: {
      onHeader(header) {
        if (signal.aborted) return;
        activeEntryStream = new PassThrough({ highWaterMark: header.size > 1048576 ? 524288 : void 0 });
        let entryStream = activeEntryStream, startOperation = () => {
          let opPromise;
          try {
            let transformed = transformHeader(header, options);
            if (!transformed) {
              entryStream.resume(), activeOps--, processQueue();
              return;
            }
            let name = normalizeHeaderName(transformed.name), target = path.join(path.resolve(directoryPath), name);
            opPromise = (pathPromises.get(target) || Promise.resolve(void 0)).then(async (priorOp) => {
              if (signal.aborted) throw signal.reason;
              if (priorOp && (priorOp === "directory" && transformed.type !== "directory" || priorOp !== "directory" && transformed.type === "directory"))
                throw new Error(`Path conflict ${transformed.type} over existing ${priorOp} at "${transformed.name}"`);
              try {
                let destDir = await destDirPromise;
                if (maxDepth !== 1 / 0 && name.split("/").length > maxDepth) throw new Error("Tar exceeds max specified depth.");
                let outPath = path.join(destDir.symbolic, name);
                validateBounds(outPath, destDir.symbolic, `Entry "${transformed.name}" points outside the extraction directory.`);
                let parentDir = path.dirname(outPath);
                switch (await ensureDirectoryExists(parentDir), transformed.type) {
                  case "directory":
                    await fs.mkdir(outPath, {
                      recursive: !0,
                      mode: dmode ?? transformed.mode
                    });
                    break;
                  case "file": {
                    let fileStream = createWriteStream(outPath, {
                      mode: fmode ?? transformed.mode,
                      highWaterMark: transformed.size > 1048576 ? 524288 : void 0
                    });
                    await pipeline(entryStream, fileStream);
                    break;
                  }
                  case "symlink": {
                    let { linkname } = transformed;
                    if (!linkname) return transformed.type;
                    let target$1 = path.resolve(parentDir, linkname);
                    validateBounds(target$1, destDir.symbolic, `Symlink "${linkname}" points outside the extraction directory.`), await fs.symlink(linkname, outPath);
                    break;
                  }
                  case "link": {
                    let { linkname } = transformed;
                    if (!linkname) return transformed.type;
                    let normalizedLink = normalizeUnicode(linkname);
                    if (path.isAbsolute(normalizedLink)) throw new Error(`Hardlink "${linkname}" points outside the extraction directory.`);
                    let linkTarget = path.join(destDir.symbolic, normalizedLink);
                    validateBounds(linkTarget, destDir.symbolic, `Hardlink "${linkname}" points outside the extraction directory.`), await ensureDirectoryExists(path.dirname(linkTarget));
                    let realTargetParent = await fs.realpath(path.dirname(linkTarget)), realLinkTarget = path.join(realTargetParent, path.basename(linkTarget));
                    if (validateBounds(realLinkTarget, destDir.real, `Hardlink "${linkname}" points outside the extraction directory.`), linkTarget === outPath) return transformed.type;
                    let targetPromise = pathPromises.get(linkTarget);
                    targetPromise && await targetPromise, await fs.link(linkTarget, outPath);
                    break;
                  }
                  default:
                    return transformed.type;
                }
                return transformed.mtime && await (transformed.type === "symlink" ? fs.lutimes : fs.utimes)(outPath, transformed.mtime, transformed.mtime).catch(() => {
                }), transformed.type;
              } finally {
                entryStream.readableEnded || entryStream.resume();
              }
            }), pathPromises.set(target, opPromise);
          } catch (err) {
            opPromise = Promise.reject(err), abortController.abort(err);
          }
          opPromise.catch((err) => abortController.abort(err)).finally(() => {
            activeOps--, processQueue();
          });
        };
        opQueue.push(startOperation), processQueue();
      },
      onData(chunk) {
        signal.aborted || activeEntryStream?.write(chunk);
      },
      onEndEntry() {
        activeEntryStream?.end(), activeEntryStream = null;
      },
      onError(error) {
        abortController.abort(error);
      },
      async process() {
        if (processingEnded = !0, processQueue(), await drainPromise, signal.aborted) throw signal.reason;
      }
    },
    signal
  };
}

// src/cli/dirs.ts
var resolveUsingBranchInstall = async (packageManager, request) => {
  let tempDirectory = await temporaryDirectory(), version = versions[request] || await packageManager.latestVersion(request), url = (src_default.default || src_default)(request, version, {
    registry: await packageManager.getRegistryURL()
  }), response = await fetch(url);
  if (!response.ok || !response.body)
    throw new Error(`Failed to download tarball from ${url}`);
  return await pipeline2(
    Readable2.fromWeb(response.body),
    createGunzip(),
    unpackTar(tempDirectory)
  ), join2(tempDirectory, "package");
};
async function getRendererDir(packageManager, renderer) {
  let externalFramework = externalFrameworks.find((framework) => framework.name === renderer), frameworkPackageName = externalFramework?.packageName || externalFramework?.renderer || `@storybook/${renderer}`, packageJsonPath = join2(frameworkPackageName, "package.json"), errors = [];
  try {
    return resolvePackageDir(frameworkPackageName, process.cwd());
  } catch (e) {
    invariant(e instanceof Error), errors.push(e);
  }
  try {
    return await resolveUsingBranchInstall(packageManager, frameworkPackageName);
  } catch (e) {
    invariant(e instanceof Error), errors.push(e);
  }
  throw new Error(`Cannot find ${packageJsonPath}, ${errors.map((e) => e.stack).join(`

`)}`);
}

// src/cli/helpers.ts
import { cpSync, existsSync, readFileSync, writeFileSync } from "node:fs";
import { cp, readFile as readFile2, writeFile } from "node:fs/promises";
import { join as join3, resolve as resolve2 } from "node:path";
import {
  frameworkToRenderer,
  getProjectRoot
} from "storybook/internal/common";
import { logger } from "storybook/internal/node-logger";
var import_picocolors = __toESM(require_picocolors(), 1);
import { coerce, satisfies } from "semver";

// ../node_modules/strip-json-comments/index.js
var singleComment = Symbol("singleComment"), multiComment = Symbol("multiComment"), stripWithoutWhitespace = () => "", stripWithWhitespace = (string, start, end) => string.slice(start, end).replace(/[^ \t\r\n]/g, " "), isEscaped = (jsonString, quotePosition) => {
  let index = quotePosition - 1, backslashCount = 0;
  for (; jsonString[index] === "\\"; )
    index -= 1, backslashCount += 1;
  return !!(backslashCount % 2);
};
function stripJsonComments(jsonString, { whitespace = !0, trailingCommas = !1 } = {}) {
  if (typeof jsonString != "string")
    throw new TypeError(`Expected argument \`jsonString\` to be a \`string\`, got \`${typeof jsonString}\``);
  let strip = whitespace ? stripWithWhitespace : stripWithoutWhitespace, isInsideString = !1, isInsideComment = !1, offset = 0, buffer = "", result = "", commaIndex = -1;
  for (let index = 0; index < jsonString.length; index++) {
    let currentCharacter = jsonString[index], nextCharacter = jsonString[index + 1];
    if (!isInsideComment && currentCharacter === '"' && (isEscaped(jsonString, index) || (isInsideString = !isInsideString)), !isInsideString)
      if (!isInsideComment && currentCharacter + nextCharacter === "//")
        buffer += jsonString.slice(offset, index), offset = index, isInsideComment = singleComment, index++;
      else if (isInsideComment === singleComment && currentCharacter + nextCharacter === `\r
`) {
        index++, isInsideComment = !1, buffer += strip(jsonString, offset, index), offset = index;
        continue;
      } else if (isInsideComment === singleComment && currentCharacter === `
`)
        isInsideComment = !1, buffer += strip(jsonString, offset, index), offset = index;
      else if (!isInsideComment && currentCharacter + nextCharacter === "/*") {
        buffer += jsonString.slice(offset, index), offset = index, isInsideComment = multiComment, index++;
        continue;
      } else if (isInsideComment === multiComment && currentCharacter + nextCharacter === "*/") {
        index++, isInsideComment = !1, buffer += strip(jsonString, offset, index + 1), offset = index + 1;
        continue;
      } else trailingCommas && !isInsideComment && (commaIndex !== -1 ? currentCharacter === "}" || currentCharacter === "]" ? (buffer += jsonString.slice(offset, index), result += strip(buffer, 0, 1) + buffer.slice(1), buffer = "", offset = index, commaIndex = -1) : currentCharacter !== " " && currentCharacter !== "	" && currentCharacter !== "\r" && currentCharacter !== `
` && (buffer += jsonString.slice(offset, index), offset = index, commaIndex = -1) : currentCharacter === "," && (result += buffer + jsonString.slice(offset, index), buffer = "", offset = index, commaIndex = index));
  }
  let remaining = isInsideComment === singleComment ? strip(jsonString, offset) : jsonString.slice(offset);
  return result + buffer + remaining;
}

// src/cli/helpers.ts
function readFileAsJson(jsonPath, allowComments) {
  let filePath = resolve2(jsonPath);
  if (!existsSync(filePath))
    return !1;
  let fileContent = readFileSync(filePath, "utf8"), jsonContent = allowComments ? stripJsonComments(fileContent) : fileContent;
  try {
    return JSON.parse(jsonContent);
  } catch (e) {
    throw logger.error(import_picocolors.default.red(`Invalid json in file: ${filePath}`)), e;
  }
}
var writeFileAsJson = (jsonPath, content) => {
  let filePath = resolve2(jsonPath);
  return existsSync(filePath) ? (writeFileSync(filePath, `${JSON.stringify(content, null, 2)}
`), !0) : !1;
};
async function getBabelDependencies(packageManager) {
  let dependenciesToAdd = [], babelLoaderVersion = "^8.0.0-0", babelCoreVersion = packageManager.getDependencyVersion("babel-core");
  if (babelCoreVersion) {
    let latestCompatibleBabelVersion = await packageManager.latestVersion(
      "babel-core",
      babelCoreVersion
    );
    latestCompatibleBabelVersion && satisfies(latestCompatibleBabelVersion, "^6.0.0") && (babelLoaderVersion = "^7.0.0");
  } else if (!packageManager.getDependencyVersion("@babel/core")) {
    let babelCoreInstallVersion = await packageManager.getVersion("@babel/core");
    dependenciesToAdd.push(`@babel/core@${babelCoreInstallVersion}`);
  }
  if (!packageManager.getDependencyVersion("babel-loader")) {
    let babelLoaderInstallVersion = await packageManager.getVersion(
      "babel-loader",
      babelLoaderVersion
    );
    dependenciesToAdd.push(`babel-loader@${babelLoaderInstallVersion}`);
  }
  return dependenciesToAdd;
}
function addToDevDependenciesIfNotPresent(packageJson, name, packageVersion) {
  !packageJson.dependencies?.[name] && !packageJson.devDependencies?.[name] && (packageJson.devDependencies ? packageJson.devDependencies[name] = packageVersion : packageJson.devDependencies = {
    [name]: packageVersion
  });
}
function copyTemplate(templateRoot, destination = ".") {
  let templateDir = resolve2(templateRoot, "template-csf/");
  if (!existsSync(templateDir))
    throw new Error("Couldn't find template dir");
  cpSync(templateDir, destination, { recursive: !0 });
}
var frameworkToDefaultBuilder = {
  angular: "webpack5" /* Webpack5 */,
  ember: "webpack5" /* Webpack5 */,
  "html-vite": "vite" /* Vite */,
  nextjs: "webpack5" /* Webpack5 */,
  nuxt: "vite" /* Vite */,
  "nextjs-vite": "vite" /* Vite */,
  "preact-vite": "vite" /* Vite */,
  qwik: "vite" /* Vite */,
  "react-native-web-vite": "vite" /* Vite */,
  "react-vite": "vite" /* Vite */,
  "react-webpack5": "webpack5" /* Webpack5 */,
  "server-webpack5": "webpack5" /* Webpack5 */,
  solid: "vite" /* Vite */,
  "svelte-vite": "vite" /* Vite */,
  sveltekit: "vite" /* Vite */,
  "vue3-vite": "vite" /* Vite */,
  "web-components-vite": "vite" /* Vite */,
  // Only to pass type checking, will never be used
  "react-rsbuild": "rsbuild" /* Rsbuild */,
  "vue3-rsbuild": "rsbuild" /* Rsbuild */
};
async function getVersionSafe(packageManager, packageName) {
  try {
    let version = await packageManager.getInstalledVersion(packageName);
    return version || (version = packageManager.getAllDependencies()[packageName] ?? ""), coerce(version, { includePrerelease: !0 })?.toString();
  } catch {
  }
}
var cliStoriesTargetPath = async () => existsSync("./src") ? "./src/stories" : "./stories";
async function copyTemplateFiles({
  packageManager,
  templateLocation,
  language,
  destination,
  commonAssetsDir,
  features
}) {
  let languageFolderMapping = {
    javascript: "js",
    typescript: "ts"
  }, templatePath = async () => {
    let baseDir = await getRendererDir(packageManager, templateLocation), assetsDir = join3(baseDir, "template", "cli"), assetsLanguage = join3(assetsDir, languageFolderMapping[language]), assetsJS = join3(assetsDir, languageFolderMapping.javascript), assetsTS = join3(assetsDir, languageFolderMapping.typescript);
    if (existsSync(assetsLanguage))
      return assetsLanguage;
    if (existsSync(assetsTS))
      return assetsTS;
    if (existsSync(assetsJS))
      return assetsJS;
    if (existsSync(assetsDir))
      return assetsDir;
    throw new Error(`Unsupported renderer: ${templateLocation} (${baseDir})`);
  }, destinationPath = destination ?? await cliStoriesTargetPath(), filter = (file) => features.includes("docs") || !file.endsWith(".mdx");
  if (commonAssetsDir && await cp(commonAssetsDir, destinationPath, { recursive: !0, filter }), await cp(await templatePath(), destinationPath, { recursive: !0, filter }), commonAssetsDir && features.includes("docs")) {
    let rendererType = frameworkToRenderer[templateLocation] || "react";
    rendererType === "vue3" && (rendererType = "vue"), await adjustTemplate(join3(destinationPath, "Configure.mdx"), { renderer: rendererType });
  }
}
async function adjustTemplate(templatePath, templateData) {
  let template = await readFile2(templatePath, { encoding: "utf8" });
  Object.keys(templateData).forEach((key) => {
    template = template.replaceAll(`{{${key}}}`, `${templateData[key]}`);
  }), await writeFile(templatePath, template);
}
async function isNxProject() {
  return up("nx.json", { last: getProjectRoot() });
}
function coerceSemver(version) {
  let coercedSemver = coerce(version);
  return invariant(coercedSemver != null, `Could not coerce ${version} into a semver.`), coercedSemver;
}
function hasStorybookDependencies(packageManager) {
  let currentPackageDeps = packageManager.getAllDependencies();
  return Object.keys(currentPackageDeps).some((dep) => dep.includes("storybook"));
}

// src/cli/detect.ts
import { existsSync as existsSync2 } from "node:fs";
import { resolve as resolve3 } from "node:path";
import { HandledError, commandLog, getProjectRoot as getProjectRoot2 } from "storybook/internal/common";
import { logger as logger2 } from "storybook/internal/node-logger";
var import_prompts = __toESM(require_prompts(), 1);
import semver from "semver";
var viteConfigFiles = ["vite.config.ts", "vite.config.js", "vite.config.mjs"], webpackConfigFiles = ["webpack.config.js"], hasDependency = (packageJson, name, matcher) => {
  let version = packageJson.dependencies?.[name] || packageJson.devDependencies?.[name];
  return version && typeof matcher == "function" ? matcher(version) : !!version;
}, hasPeerDependency = (packageJson, name, matcher) => {
  let version = packageJson.peerDependencies?.[name];
  return version && typeof matcher == "function" ? matcher(version) : !!version;
}, getFrameworkPreset = (packageJson, framework) => {
  let matcher = {
    dependencies: [!1],
    peerDependencies: [!1],
    files: [!1]
  }, { preset, files, dependencies, peerDependencies, matcherFunction } = framework, dependencySearches = [];
  Array.isArray(dependencies) ? dependencySearches = dependencies.map((name) => [name, void 0]) : typeof dependencies == "object" && (dependencySearches = Object.entries(dependencies)), dependencySearches.length > 0 && (matcher.dependencies = dependencySearches.map(
    ([name, matchFn]) => hasDependency(packageJson, name, matchFn)
  ));
  let peerDependencySearches = [];
  return Array.isArray(peerDependencies) ? peerDependencySearches = peerDependencies.map((name) => [name, void 0]) : typeof peerDependencies == "object" && (peerDependencySearches = Object.entries(peerDependencies)), peerDependencySearches.length > 0 && (matcher.peerDependencies = peerDependencySearches.map(
    ([name, matchFn]) => hasPeerDependency(packageJson, name, matchFn)
  )), Array.isArray(files) && files.length > 0 && (matcher.files = files.map((name) => existsSync2(name))), matcherFunction(matcher) ? preset : null;
};
function detectFrameworkPreset(packageJson = {}) {
  let result = [...supportedTemplates, unsupportedTemplate].find((framework) => getFrameworkPreset(packageJson, framework) !== null);
  return result ? result.preset : "UNDETECTED" /* UNDETECTED */;
}
async function detectBuilder(packageManager, projectType) {
  let viteConfig = any(viteConfigFiles, { last: getProjectRoot2() }), webpackConfig = any(webpackConfigFiles, { last: getProjectRoot2() }), dependencies = packageManager.getAllDependencies();
  if (viteConfig || dependencies.vite && dependencies.webpack === void 0)
    return commandLog("Detected Vite project. Setting builder to Vite")(), "vite" /* Vite */;
  if (webpackConfig || (dependencies.webpack || dependencies["@nuxt/webpack-builder"]) && dependencies.vite !== void 0)
    return commandLog("Detected webpack project. Setting builder to webpack")(), "webpack5" /* Webpack5 */;
  switch (projectType) {
    case "REACT_NATIVE_AND_RNW" /* REACT_NATIVE_AND_RNW */:
    case "REACT_NATIVE_WEB" /* REACT_NATIVE_WEB */:
      return "vite" /* Vite */;
    case "REACT_SCRIPTS" /* REACT_SCRIPTS */:
    case "ANGULAR" /* ANGULAR */:
    case "REACT_NATIVE" /* REACT_NATIVE */:
    // technically react native doesn't use webpack, we just want to set something
    case "NEXTJS" /* NEXTJS */:
    case "EMBER" /* EMBER */:
      return "webpack5" /* Webpack5 */;
    case "NUXT" /* NUXT */:
      return "vite" /* Vite */;
    default:
      let { builder } = await (0, import_prompts.default)(
        {
          type: "select",
          name: "builder",
          message: `
We were not able to detect the right builder for your project. Please select one:`,
          choices: [
            { title: "Vite", value: "vite" /* Vite */ },
            { title: "Webpack 5", value: "webpack5" /* Webpack5 */ }
          ]
        },
        {
          onCancel: () => {
            throw new HandledError("Canceled by the user");
          }
        }
      );
      return builder;
  }
}
function isStorybookInstantiated(configDir = resolve3(process.cwd(), ".storybook")) {
  return existsSync2(configDir);
}
async function detectPnp() {
  return !!any([".pnp.js", ".pnp.cjs"]);
}
async function detectLanguage(packageManager) {
  let language = "javascript" /* JAVASCRIPT */;
  if (existsSync2("jsconfig.json"))
    return language;
  let isTypescriptDirectDependency = !!packageManager.getAllDependencies().typescript, getModulePackageJSONVersion = async (pkg) => (await packageManager.getModulePackageJSON(pkg))?.version ?? null, [
    typescriptVersion,
    prettierVersion,
    babelPluginTransformTypescriptVersion,
    typescriptEslintParserVersion,
    eslintPluginStorybookVersion
  ] = await Promise.all([
    getModulePackageJSONVersion("typescript"),
    getModulePackageJSONVersion("prettier"),
    getModulePackageJSONVersion("@babel/plugin-transform-typescript"),
    getModulePackageJSONVersion("@typescript-eslint/parser"),
    getModulePackageJSONVersion("eslint-plugin-storybook")
  ]);
  return isTypescriptDirectDependency && typescriptVersion ? semver.gte(typescriptVersion, "4.9.0") && (!prettierVersion || semver.gte(prettierVersion, "2.8.0")) && (!babelPluginTransformTypescriptVersion || semver.gte(babelPluginTransformTypescriptVersion, "7.20.0")) && (!typescriptEslintParserVersion || semver.gte(typescriptEslintParserVersion, "5.44.0")) && (!eslintPluginStorybookVersion || semver.gte(eslintPluginStorybookVersion, "0.6.8")) ? language = "typescript" /* TYPESCRIPT */ : logger2.warn(
    "Detected TypeScript < 4.9 or incompatible tooling, populating with JavaScript examples"
  ) : existsSync2("tsconfig.json") && (language = "typescript" /* TYPESCRIPT */), language;
}
async function detect(packageManager, options = {}) {
  try {
    if (await isNxProject())
      return "NX" /* NX */;
    if (options.html)
      return "HTML" /* HTML */;
    let { packageJson } = packageManager.primaryPackageJson;
    return detectFrameworkPreset(packageJson);
  } catch {
    return "UNDETECTED" /* UNDETECTED */;
  }
}

export {
  externalFrameworks,
  SUPPORTED_RENDERERS,
  ProjectType,
  CoreBuilder,
  CoreWebpackCompilers,
  CommunityBuilder,
  compilerNameToCoreCompiler,
  builderNameToCoreBuilder,
  SupportedLanguage,
  supportedTemplates,
  unsupportedTemplate,
  installableProjectTypes,
  getRendererDir,
  readFileAsJson,
  writeFileAsJson,
  getBabelDependencies,
  addToDevDependenciesIfNotPresent,
  copyTemplate,
  frameworkToDefaultBuilder,
  getVersionSafe,
  cliStoriesTargetPath,
  copyTemplateFiles,
  adjustTemplate,
  isNxProject,
  coerceSemver,
  hasStorybookDependencies,
  detectFrameworkPreset,
  detectBuilder,
  isStorybookInstantiated,
  detectPnp,
  detectLanguage,
  detect
};
