codebase-snapshot 0.9.4 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,14 @@
1
1
  import * as crypto from 'crypto';
2
2
  import { createHash } from 'crypto';
3
3
  import { AsyncLocalStorage } from 'async_hooks';
4
- import * as fs11 from 'fs';
4
+ import * as fs12 from 'fs';
5
5
  import * as os from 'os';
6
- import * as path12 from 'path';
6
+ import * as path13 from 'path';
7
7
  import ts from 'typescript';
8
8
  import { createRequire } from 'module';
9
9
  import { pathToFileURL } from 'url';
10
10
  import * as childProcess from 'child_process';
11
+ import * as https from 'https';
11
12
  import * as readline from 'readline';
12
13
 
13
14
  // src/index.ts
@@ -234,9 +235,9 @@ var JAVA_METHOD = /^\s+(?:public|private|protected)\s+(?:static\s+)?(?:final\s+)
234
235
  var jvmProfile = {
235
236
  id: "jvm",
236
237
  extensions: [".java", ".kt", ".kts", ".scala"],
237
- summarize(path13, content) {
238
+ summarize(path14, content) {
238
239
  const summary = emptySummary();
239
- const lower = path13.toLowerCase();
240
+ const lower = path14.toLowerCase();
240
241
  const isJava = lower.endsWith(".java");
241
242
  const isKotlin = lower.endsWith(".kt") || lower.endsWith(".kts");
242
243
  eachLine(content, (line) => {
@@ -689,16 +690,16 @@ function summarizeTypeScriptSource(relativePath, content) {
689
690
  // src/ast/profiles/sfc.ts
690
691
  var SCRIPT_BLOCK = /<script[^>]*>([\s\S]*?)<\/script>/gi;
691
692
  var ASTRO_FRONTMATTER = /^\uFEFF?---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*(?=\r?\n|$)/;
692
- function componentName(path13) {
693
- const base = path13.split("/").pop() ?? path13;
693
+ function componentName(path14) {
694
+ const base = path14.split("/").pop() ?? path14;
694
695
  return base.replace(/\.[^.]+$/, "");
695
696
  }
696
697
  var sfcProfile = {
697
698
  id: "sfc",
698
699
  extensions: [".vue", ".svelte", ".astro"],
699
- summarize(path13, content) {
700
+ summarize(path14, content) {
700
701
  let script = "";
701
- if (path13.toLowerCase().endsWith(".astro")) {
702
+ if (path14.toLowerCase().endsWith(".astro")) {
702
703
  const frontmatter = ASTRO_FRONTMATTER.exec(content);
703
704
  if (frontmatter) script += `${frontmatter[1]}
704
705
  `;
@@ -707,7 +708,7 @@ var sfcProfile = {
707
708
  script += `${match[1]}
708
709
  `;
709
710
  }
710
- const name = componentName(path13);
711
+ const name = componentName(path14);
711
712
  if (!script.trim()) {
712
713
  const summary2 = emptySummary();
713
714
  if (name) {
@@ -741,15 +742,15 @@ for (const profile of LANGUAGE_PROFILES) {
741
742
  BY_EXTENSION.set(extension.toLowerCase(), profile);
742
743
  }
743
744
  }
744
- function profileForPath(path13) {
745
- const lower = path13.toLowerCase();
745
+ function profileForPath(path14) {
746
+ const lower = path14.toLowerCase();
746
747
  const dot = lower.lastIndexOf(".");
747
748
  if (dot === -1) return null;
748
749
  return BY_EXTENSION.get(lower.slice(dot)) ?? null;
749
750
  }
750
- function summarizeWithProfile(path13, content) {
751
- const profile = profileForPath(path13);
752
- return profile ? profile.summarize(path13, content) : null;
751
+ function summarizeWithProfile(path14, content) {
752
+ const profile = profileForPath(path14);
753
+ return profile ? profile.summarize(path14, content) : null;
753
754
  }
754
755
 
755
756
  // src/ast/structured.ts
@@ -920,15 +921,15 @@ var SKIPPED_WALK_DIRS = /* @__PURE__ */ new Set([
920
921
  ]);
921
922
  function readSmallFile(fullPath) {
922
923
  try {
923
- const stats = fs11.statSync(fullPath);
924
+ const stats = fs12.statSync(fullPath);
924
925
  if (!stats.isFile() || stats.size > MANIFEST_MAX_BYTES) return null;
925
- return fs11.readFileSync(fullPath, "utf8");
926
+ return fs12.readFileSync(fullPath, "utf8");
926
927
  } catch {
927
928
  return null;
928
929
  }
929
930
  }
930
931
  function readManifest(cwd, name) {
931
- return readSmallFile(path12.join(cwd, name));
932
+ return readSmallFile(path13.join(cwd, name));
932
933
  }
933
934
  function dependenciesFromPackageJson(raw) {
934
935
  const names = /* @__PURE__ */ new Set();
@@ -988,7 +989,7 @@ function pnpmWorkspacePatterns(raw) {
988
989
  function childDirectories(cwd, parent) {
989
990
  let entries;
990
991
  try {
991
- entries = fs11.readdirSync(path12.join(cwd, parent), { withFileTypes: true });
992
+ entries = fs12.readdirSync(path13.join(cwd, parent), { withFileTypes: true });
992
993
  } catch {
993
994
  return [];
994
995
  }
@@ -1024,12 +1025,12 @@ function scanWorkspacePackages(cwd, patterns) {
1024
1025
  const files = /* @__PURE__ */ new Set();
1025
1026
  const dependencies = /* @__PURE__ */ new Set();
1026
1027
  for (const relative7 of workspacePackageDirs(cwd, patterns)) {
1027
- const full = path12.join(cwd, relative7);
1028
+ const full = path13.join(cwd, relative7);
1028
1029
  try {
1029
- for (const entry of fs11.readdirSync(full, { withFileTypes: true })) files.add(entry.name);
1030
+ for (const entry of fs12.readdirSync(full, { withFileTypes: true })) files.add(entry.name);
1030
1031
  } catch {
1031
1032
  }
1032
- const raw = readSmallFile(path12.join(full, "package.json"));
1033
+ const raw = readSmallFile(path13.join(full, "package.json"));
1033
1034
  if (raw !== null) {
1034
1035
  for (const name of dependenciesFromPackageJson(raw)) dependencies.add(name);
1035
1036
  }
@@ -1046,7 +1047,7 @@ function countMarkdownFiles(cwd) {
1046
1047
  directoriesSeen += 1;
1047
1048
  let entries;
1048
1049
  try {
1049
- entries = fs11.readdirSync(current.dir, { withFileTypes: true });
1050
+ entries = fs12.readdirSync(current.dir, { withFileTypes: true });
1050
1051
  } catch {
1051
1052
  continue;
1052
1053
  }
@@ -1057,7 +1058,7 @@ function countMarkdownFiles(cwd) {
1057
1058
  }
1058
1059
  if (!entry.isDirectory() || current.depth >= 2) continue;
1059
1060
  if (entry.name.startsWith(".") || SKIPPED_WALK_DIRS.has(entry.name)) continue;
1060
- queue.push({ dir: path12.join(current.dir, entry.name), depth: current.depth + 1 });
1061
+ queue.push({ dir: path13.join(current.dir, entry.name), depth: current.depth + 1 });
1061
1062
  }
1062
1063
  }
1063
1064
  return count;
@@ -1066,7 +1067,7 @@ function buildPresetContext(cwd) {
1066
1067
  const files = /* @__PURE__ */ new Set();
1067
1068
  const dirs = /* @__PURE__ */ new Set();
1068
1069
  try {
1069
- for (const entry of fs11.readdirSync(cwd, { withFileTypes: true })) {
1070
+ for (const entry of fs12.readdirSync(cwd, { withFileTypes: true })) {
1070
1071
  if (entry.isDirectory()) dirs.add(entry.name);
1071
1072
  else if (entry.isFile()) files.add(entry.name);
1072
1073
  }
@@ -1083,7 +1084,7 @@ function buildPresetContext(cwd) {
1083
1084
  const isWorkspace = files.has("pnpm-workspace.yaml") || files.has("nx.json") || files.has("turbo.json") || files.has("lerna.json") || packageJson !== void 0 && packageJson.includes('"workspaces"') || declaredWorkspaces.length > 0;
1084
1085
  let workspace = { files: /* @__PURE__ */ new Set(), dependencies: /* @__PURE__ */ new Set() };
1085
1086
  if (isWorkspace) {
1086
- const pnpmRaw = files.has("pnpm-workspace.yaml") ? readSmallFile(path12.join(cwd, "pnpm-workspace.yaml")) : null;
1087
+ const pnpmRaw = files.has("pnpm-workspace.yaml") ? readSmallFile(path13.join(cwd, "pnpm-workspace.yaml")) : null;
1087
1088
  const declared = pnpmRaw === null ? [] : pnpmWorkspacePatterns(pnpmRaw);
1088
1089
  const patterns = declared.length > 0 ? declared : declaredWorkspaces.length > 0 ? declaredWorkspaces : DEFAULT_WORKSPACE_PATTERNS;
1089
1090
  workspace = scanWorkspacePackages(cwd, patterns);
@@ -2358,14 +2359,14 @@ var PRESET_IGNORES = new Set(
2358
2359
  );
2359
2360
  function readLinkTarget(linkPath, fallback) {
2360
2361
  try {
2361
- return fs11.readlinkSync(linkPath);
2362
+ return fs12.readlinkSync(linkPath);
2362
2363
  } catch {
2363
2364
  return fallback;
2364
2365
  }
2365
2366
  }
2366
2367
  function isInside(root, candidate) {
2367
- const relative7 = path12.relative(root, candidate);
2368
- return relative7 === "" || !relative7.startsWith(`..${path12.sep}`) && relative7 !== ".." && !path12.isAbsolute(relative7);
2368
+ const relative7 = path13.relative(root, candidate);
2369
+ return relative7 === "" || !relative7.startsWith(`..${path13.sep}`) && relative7 !== ".." && !path13.isAbsolute(relative7);
2369
2370
  }
2370
2371
  function getGitInfo(cwd, fallbackBranch = "main") {
2371
2372
  try {
@@ -2570,10 +2571,10 @@ function trimUnescapedTrailingSpaces(line) {
2570
2571
  return line.slice(0, end);
2571
2572
  }
2572
2573
  function readGitignoreRules(dir) {
2573
- const gitignorePath2 = path12.join(dir, ".gitignore");
2574
+ const gitignorePath2 = path13.join(dir, ".gitignore");
2574
2575
  let raw;
2575
2576
  try {
2576
- raw = fs11.readFileSync(gitignorePath2, "utf8");
2577
+ raw = fs12.readFileSync(gitignorePath2, "utf8");
2577
2578
  } catch {
2578
2579
  return [];
2579
2580
  }
@@ -2700,7 +2701,7 @@ function isToolOwnedDirName(name) {
2700
2701
  }
2701
2702
  function hasSnapshotMarker(target) {
2702
2703
  try {
2703
- return fs11.statSync(target).isDirectory() && fs11.existsSync(path12.join(target, ".codebase-snapshot"));
2704
+ return fs12.statSync(target).isDirectory() && fs12.existsSync(path13.join(target, ".codebase-snapshot"));
2704
2705
  } catch {
2705
2706
  return false;
2706
2707
  }
@@ -2714,7 +2715,7 @@ function makeToolOwnedDecider(cwd, toolOwnedPaths) {
2714
2715
  const prefix = parts.slice(0, depth).join("/");
2715
2716
  let hasMarker = markers.get(prefix);
2716
2717
  if (hasMarker === void 0) {
2717
- hasMarker = fs11.existsSync(path12.join(cwd, prefix, ".codebase-snapshot"));
2718
+ hasMarker = fs12.existsSync(path13.join(cwd, prefix, ".codebase-snapshot"));
2718
2719
  markers.set(prefix, hasMarker);
2719
2720
  }
2720
2721
  if (hasMarker) return true;
@@ -2729,7 +2730,7 @@ function makeLinkProbe() {
2729
2730
  let known = cache.get(absolutePath);
2730
2731
  if (known === void 0) {
2731
2732
  try {
2732
- known = fs11.lstatSync(absolutePath).isSymbolicLink();
2733
+ known = fs12.lstatSync(absolutePath).isSymbolicLink();
2733
2734
  } catch {
2734
2735
  known = false;
2735
2736
  }
@@ -2742,7 +2743,7 @@ function dropLinkedDirectories(cwd, candidates, skipped) {
2742
2743
  const isLink = makeLinkProbe();
2743
2744
  let rootReal = cwd;
2744
2745
  try {
2745
- rootReal = fs11.realpathSync(cwd);
2746
+ rootReal = fs12.realpathSync(cwd);
2746
2747
  } catch {
2747
2748
  }
2748
2749
  const reported = /* @__PURE__ */ new Set();
@@ -2752,7 +2753,7 @@ function dropLinkedDirectories(cwd, candidates, skipped) {
2752
2753
  let linkedDir = null;
2753
2754
  for (let depth = 1; depth <= parts.length; depth += 1) {
2754
2755
  const prefix = parts.slice(0, depth).join("/");
2755
- if (isLink(path12.join(cwd, prefix))) {
2756
+ if (isLink(path13.join(cwd, prefix))) {
2756
2757
  linkedDir = prefix;
2757
2758
  break;
2758
2759
  }
@@ -2763,10 +2764,10 @@ function dropLinkedDirectories(cwd, candidates, skipped) {
2763
2764
  }
2764
2765
  if (reported.has(linkedDir)) continue;
2765
2766
  reported.add(linkedDir);
2766
- const absolute = path12.join(cwd, linkedDir);
2767
+ const absolute = path13.join(cwd, linkedDir);
2767
2768
  let targetReal = absolute;
2768
2769
  try {
2769
- targetReal = fs11.realpathSync(absolute);
2770
+ targetReal = fs12.realpathSync(absolute);
2770
2771
  } catch {
2771
2772
  }
2772
2773
  const target = readLinkTarget(absolute, targetReal);
@@ -2843,7 +2844,7 @@ function collectFiles(cwd, options = {}) {
2843
2844
  "Discovery mode is `git`, but git could not list this directory's files. Run inside a working repository, or pass --discovery walk (or auto) to scan the tree directly."
2844
2845
  );
2845
2846
  }
2846
- if (fs11.existsSync(path12.join(cwd, ".git"))) {
2847
+ if (fs12.existsSync(path13.join(cwd, ".git"))) {
2847
2848
  throw new Error(
2848
2849
  "This directory is a git repository, but git could not list its files. A plain walk honours .gitignore files, but git also applies .git/info/exclude and your global excludes file, includes files that are tracked although a .gitignore now matches them, and treats a submodule as a single entry. Fix the repository (git status should work), run outside git, or pass --discovery walk to accept those differences."
2849
2850
  );
@@ -2902,7 +2903,7 @@ function collectFiles(cwd, options = {}) {
2902
2903
  }
2903
2904
  function rootRealFor(root) {
2904
2905
  try {
2905
- return fs11.realpathSync(root);
2906
+ return fs12.realpathSync(root);
2906
2907
  } catch {
2907
2908
  return root;
2908
2909
  }
@@ -2910,18 +2911,18 @@ function rootRealFor(root) {
2910
2911
  function walkDirectory(dir, baseDir, rootReal, visited, reservedPaths = /* @__PURE__ */ new Set(), parentGitignoreLayers = []) {
2911
2912
  const results = { files: [], skipped: [] };
2912
2913
  const stack = [];
2913
- const relativeToBase = (target) => path12.relative(baseDir, target).replace(/\\/g, "/") || ".";
2914
+ const relativeToBase = (target) => path13.relative(baseDir, target).replace(/\\/g, "/") || ".";
2914
2915
  const enter = (current, layers) => {
2915
2916
  if (visited.has(current)) return false;
2916
2917
  visited.add(current);
2917
2918
  const localRules = readGitignoreRules(current);
2918
2919
  const gitignoreLayers = localRules.length === 0 ? layers : [
2919
2920
  ...layers,
2920
- { prefix: path12.relative(baseDir, current).replace(/\\/g, "/"), rules: localRules }
2921
+ { prefix: path13.relative(baseDir, current).replace(/\\/g, "/"), rules: localRules }
2921
2922
  ];
2922
2923
  let entries;
2923
2924
  try {
2924
- entries = fs11.readdirSync(current, { withFileTypes: true });
2925
+ entries = fs12.readdirSync(current, { withFileTypes: true });
2925
2926
  } catch {
2926
2927
  results.skipped.push({
2927
2928
  path: relativeToBase(current),
@@ -2943,8 +2944,8 @@ function walkDirectory(dir, baseDir, rootReal, visited, reservedPaths = /* @__PU
2943
2944
  }
2944
2945
  const entry = frame.entries[frame.index];
2945
2946
  frame.index += 1;
2946
- const fullPath = path12.join(frame.dir, entry.name);
2947
- const relPath = path12.relative(baseDir, fullPath).replace(/\\/g, "/");
2947
+ const fullPath = path13.join(frame.dir, entry.name);
2948
+ const relPath = path13.relative(baseDir, fullPath).replace(/\\/g, "/");
2948
2949
  if (isToolOwnedDirName(entry.name) && reservedPaths.has(relPath)) continue;
2949
2950
  if (DEFAULT_IGNORED_DIRS.includes(entry.name)) {
2950
2951
  results.skipped.push({
@@ -2977,14 +2978,14 @@ function walkDirectory(dir, baseDir, rootReal, visited, reservedPaths = /* @__PU
2977
2978
  if (entry.isSymbolicLink()) {
2978
2979
  let targetReal;
2979
2980
  try {
2980
- targetReal = fs11.realpathSync(fullPath);
2981
+ targetReal = fs12.realpathSync(fullPath);
2981
2982
  } catch {
2982
2983
  results.skipped.push({ path: relPath, reason: "read-error", detail: "broken symlink" });
2983
2984
  continue;
2984
2985
  }
2985
2986
  let stats;
2986
2987
  try {
2987
- stats = fs11.statSync(fullPath);
2988
+ stats = fs12.statSync(fullPath);
2988
2989
  } catch {
2989
2990
  results.skipped.push({ path: relPath, reason: "read-error", detail: "unreadable symlink" });
2990
2991
  continue;
@@ -3039,13 +3040,13 @@ var CONFIG_FILENAMES = [
3039
3040
  ];
3040
3041
  function findConfigFile(cwd) {
3041
3042
  for (const filename of CONFIG_FILENAMES) {
3042
- const fullPath = path12.join(cwd, filename);
3043
- if (fs11.existsSync(fullPath)) return fullPath;
3043
+ const fullPath = path13.join(cwd, filename);
3044
+ if (fs12.existsSync(fullPath)) return fullPath;
3044
3045
  }
3045
- const pkgJsonPath = path12.join(cwd, "package.json");
3046
- if (!fs11.existsSync(pkgJsonPath)) return null;
3046
+ const pkgJsonPath = path13.join(cwd, "package.json");
3047
+ if (!fs12.existsSync(pkgJsonPath)) return null;
3047
3048
  try {
3048
- const parsed = JSON.parse(fs11.readFileSync(pkgJsonPath, "utf8"));
3049
+ const parsed = JSON.parse(fs12.readFileSync(pkgJsonPath, "utf8"));
3049
3050
  return parsed.snapshot === void 0 ? null : pkgJsonPath;
3050
3051
  } catch {
3051
3052
  return null;
@@ -3296,11 +3297,11 @@ async function loadConfigFileDetailed(cwd) {
3296
3297
  const warnings = [];
3297
3298
  const errors = [];
3298
3299
  for (const filename of CONFIG_FILENAMES) {
3299
- const fullPath = path12.join(cwd, filename);
3300
- if (!fs11.existsSync(fullPath)) continue;
3300
+ const fullPath = path13.join(cwd, filename);
3301
+ if (!fs12.existsSync(fullPath)) continue;
3301
3302
  if (filename.endsWith(".json") || filename === ".snapshotrc") {
3302
3303
  try {
3303
- const config = parseJsonish(fs11.readFileSync(fullPath, "utf8"), fullPath);
3304
+ const config = parseJsonish(fs12.readFileSync(fullPath, "utf8"), fullPath);
3304
3305
  if (config === null || typeof config !== "object" || Array.isArray(config)) {
3305
3306
  throw new Error(
3306
3307
  `${fullPath} does not hold a configuration object (received ${describeValue2(config)}).`
@@ -3334,10 +3335,10 @@ async function loadConfigFileDetailed(cwd) {
3334
3335
  continue;
3335
3336
  }
3336
3337
  }
3337
- const pkgJsonPath = path12.join(cwd, "package.json");
3338
- if (fs11.existsSync(pkgJsonPath)) {
3338
+ const pkgJsonPath = path13.join(cwd, "package.json");
3339
+ if (fs12.existsSync(pkgJsonPath)) {
3339
3340
  try {
3340
- const parsed = parseJsonish(fs11.readFileSync(pkgJsonPath, "utf8"), pkgJsonPath);
3341
+ const parsed = parseJsonish(fs12.readFileSync(pkgJsonPath, "utf8"), pkgJsonPath);
3341
3342
  const snapshotKey = parsed.snapshot;
3342
3343
  if (snapshotKey && typeof snapshotKey === "object" && !Array.isArray(snapshotKey)) {
3343
3344
  return { config: snapshotKey, file: pkgJsonPath, warnings, errors };
@@ -3360,7 +3361,7 @@ async function loadConfigFile(cwd) {
3360
3361
  const loaded = await loadConfigFileDetailed(cwd);
3361
3362
  if (loaded.config && loaded.file && typeof loaded.config === "object") {
3362
3363
  Object.defineProperty(loaded.config, CONFIG_DIR_SYMBOL, {
3363
- value: path12.dirname(loaded.file),
3364
+ value: path13.dirname(loaded.file),
3364
3365
  enumerable: false,
3365
3366
  configurable: true
3366
3367
  });
@@ -3519,9 +3520,9 @@ function resolveKindRules(value) {
3519
3520
  function outputExcludePatterns(cwd, outDir, tmpDir) {
3520
3521
  const patterns = [];
3521
3522
  for (const dir of [outDir, tmpDir]) {
3522
- const absolute = path12.resolve(cwd, dir);
3523
- const relative7 = path12.relative(cwd, absolute);
3524
- if (!relative7 || relative7 === ".." || relative7.startsWith(`..${path12.sep}`) || path12.isAbsolute(relative7)) {
3523
+ const absolute = path13.resolve(cwd, dir);
3524
+ const relative7 = path13.relative(cwd, absolute);
3525
+ if (!relative7 || relative7 === ".." || relative7.startsWith(`..${path13.sep}`) || path13.isAbsolute(relative7)) {
3525
3526
  continue;
3526
3527
  }
3527
3528
  patterns.push(`${relative7.replace(/\\/g, "/")}/**`);
@@ -3640,11 +3641,11 @@ function resolveCandidateCwd(userConfig, cliOptions, baseDir) {
3640
3641
  );
3641
3642
  }
3642
3643
  const candidate = cliOptions?.cwd || userConfig?.cwd || baseDir || process.cwd();
3643
- const resolved = path12.resolve(candidate);
3644
- if (!fs11.existsSync(resolved)) {
3644
+ const resolved = path13.resolve(candidate);
3645
+ if (!fs12.existsSync(resolved)) {
3645
3646
  throw new Error(`Working directory does not exist: ${resolved}`);
3646
3647
  }
3647
- if (!fs11.statSync(resolved).isDirectory()) {
3648
+ if (!fs12.statSync(resolved).isDirectory()) {
3648
3649
  throw new Error(`Working directory is not a directory: ${resolved}`);
3649
3650
  }
3650
3651
  return resolved;
@@ -4668,7 +4669,7 @@ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
4668
4669
  ".so"
4669
4670
  ]);
4670
4671
  function isBinaryExtension(filePath) {
4671
- const ext = path12.extname(filePath).toLowerCase();
4672
+ const ext = path13.extname(filePath).toLowerCase();
4672
4673
  return BINARY_EXTENSIONS.has(ext);
4673
4674
  }
4674
4675
  function isBinaryBuffer(buffer) {
@@ -4838,13 +4839,13 @@ function isBinaryFile(absolutePath) {
4838
4839
  if (isBinaryExtension(absolutePath)) return true;
4839
4840
  let fd;
4840
4841
  try {
4841
- fd = fs11.openSync(absolutePath, "r");
4842
+ fd = fs12.openSync(absolutePath, "r");
4842
4843
  const buffer = Buffer.alloc(CHUNK);
4843
4844
  let sample;
4844
4845
  let position = 0;
4845
4846
  while (position < BINARY_SCAN_BYTES) {
4846
4847
  const wanted = Math.min(CHUNK, BINARY_SCAN_BYTES - position);
4847
- const bytesRead = fs11.readSync(fd, buffer, 0, wanted, position);
4848
+ const bytesRead = fs12.readSync(fd, buffer, 0, wanted, position);
4848
4849
  if (bytesRead === 0) return false;
4849
4850
  const chunk = buffer.subarray(0, bytesRead);
4850
4851
  if (sample === void 0) {
@@ -4862,7 +4863,7 @@ function isBinaryFile(absolutePath) {
4862
4863
  } finally {
4863
4864
  if (fd !== void 0) {
4864
4865
  try {
4865
- fs11.closeSync(fd);
4866
+ fs12.closeSync(fd);
4866
4867
  } catch {
4867
4868
  }
4868
4869
  }
@@ -4922,10 +4923,10 @@ var LANGUAGE_BY_BASENAME = {
4922
4923
  };
4923
4924
  function detectLanguage(filePath) {
4924
4925
  const normalized = filePath.replace(/\\/g, "/");
4925
- const base = path12.posix.basename(normalized);
4926
+ const base = path13.posix.basename(normalized);
4926
4927
  if (LANGUAGE_BY_BASENAME[base]) return LANGUAGE_BY_BASENAME[base];
4927
4928
  if (base === ".env" || base.startsWith(".env.")) return "dotenv";
4928
- const ext = path12.posix.extname(base).toLowerCase();
4929
+ const ext = path13.posix.extname(base).toLowerCase();
4929
4930
  return LANGUAGE_BY_EXTENSION[ext] ?? "text";
4930
4931
  }
4931
4932
  function maskedPath(value, secretRules) {
@@ -4933,33 +4934,33 @@ function maskedPath(value, secretRules) {
4933
4934
  }
4934
4935
  function confineToDirectory(directory, filename) {
4935
4936
  if (filename.includes("\0")) return null;
4936
- if (path12.isAbsolute(filename)) return null;
4937
- const base = path12.resolve(directory);
4938
- const resolved = path12.resolve(base, filename);
4937
+ if (path13.isAbsolute(filename)) return null;
4938
+ const base = path13.resolve(directory);
4939
+ const resolved = path13.resolve(base, filename);
4939
4940
  const caseInsensitive = process.platform === "win32" || process.platform === "darwin";
4940
- const prefix = caseInsensitive ? `${base}${path12.sep}`.toLowerCase() : `${base}${path12.sep}`;
4941
+ const prefix = caseInsensitive ? `${base}${path13.sep}`.toLowerCase() : `${base}${path13.sep}`;
4941
4942
  const candidate = caseInsensitive ? resolved.toLowerCase() : resolved;
4942
4943
  return candidate.startsWith(prefix) ? resolved : null;
4943
4944
  }
4944
4945
  function findStagingDirectory(config) {
4945
- const tmpDir = path12.resolve(config.cwd, config.tmpDir);
4946
+ const tmpDir = path13.resolve(config.cwd, config.tmpDir);
4946
4947
  let entries;
4947
4948
  try {
4948
- entries = fs11.readdirSync(tmpDir);
4949
+ entries = fs12.readdirSync(tmpDir);
4949
4950
  } catch {
4950
4951
  return null;
4951
4952
  }
4952
4953
  const runs = entries.filter((name) => name.startsWith("run-")).sort();
4953
4954
  const newest = runs[runs.length - 1];
4954
- return newest ? path12.join(tmpDir, newest) : null;
4955
+ return newest ? path13.join(tmpDir, newest) : null;
4955
4956
  }
4956
4957
  function describeMissingManifest(config, manifestPath) {
4957
- const outDir = path12.resolve(config.cwd, config.outDir);
4958
- const markerPath = path12.join(outDir, ".codebase-snapshot");
4958
+ const outDir = path13.resolve(config.cwd, config.outDir);
4959
+ const markerPath = path13.join(outDir, ".codebase-snapshot");
4959
4960
  let marker2 = null;
4960
4961
  try {
4961
- if (fs11.existsSync(markerPath)) {
4962
- const parsed = JSON.parse(fs11.readFileSync(markerPath, "utf8"));
4962
+ if (fs12.existsSync(markerPath)) {
4963
+ const parsed = JSON.parse(fs12.readFileSync(markerPath, "utf8"));
4963
4964
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
4964
4965
  marker2 = parsed;
4965
4966
  }
@@ -4995,14 +4996,14 @@ function sha256Hex(buffer) {
4995
4996
  }
4996
4997
  var VERIFY_SNIFF_MAX_BYTES = 8 * 1024 * 1024;
4997
4998
  function wouldNowBeIncluded(cwd, relativePath, reason) {
4998
- const absolutePath = path12.join(cwd, relativePath);
4999
+ const absolutePath = path13.join(cwd, relativePath);
4999
5000
  try {
5000
- const stats = fs11.statSync(absolutePath);
5001
+ const stats = fs12.statSync(absolutePath);
5001
5002
  if (!stats.isFile()) return false;
5002
5003
  if (isBinaryFile(absolutePath)) return false;
5003
5004
  if (reason !== "binary") return true;
5004
5005
  if (stats.size > VERIFY_SNIFF_MAX_BYTES) return false;
5005
- return !decodeText(fs11.readFileSync(absolutePath)).binary;
5006
+ return !decodeText(fs12.readFileSync(absolutePath)).binary;
5006
5007
  } catch {
5007
5008
  return false;
5008
5009
  }
@@ -5060,8 +5061,8 @@ function describeManifestShapeProblem(value) {
5060
5061
  function validateSnapshot(configInput) {
5061
5062
  assertUsableConfigInput(configInput);
5062
5063
  const config = isResolvedConfig(configInput) ? normalizeResolvedConfig(configInput) : resolveConfig(configInput);
5063
- const manifestPath = path12.resolve(config.cwd, config.outDir, "manifest.json");
5064
- if (!fs11.existsSync(manifestPath)) {
5064
+ const manifestPath = path13.resolve(config.cwd, config.outDir, "manifest.json");
5065
+ if (!fs12.existsSync(manifestPath)) {
5065
5066
  return {
5066
5067
  valid: false,
5067
5068
  manifestPresent: false,
@@ -5072,7 +5073,7 @@ function validateSnapshot(configInput) {
5072
5073
  }
5073
5074
  let manifest;
5074
5075
  try {
5075
- manifest = JSON.parse(fs11.readFileSync(manifestPath, "utf8"));
5076
+ manifest = JSON.parse(fs12.readFileSync(manifestPath, "utf8"));
5076
5077
  } catch (err) {
5077
5078
  return {
5078
5079
  valid: false,
@@ -5094,7 +5095,7 @@ function validateSnapshot(configInput) {
5094
5095
  }
5095
5096
  const drift = emptyDrift();
5096
5097
  const warnings = [];
5097
- const snapshotDir = path12.resolve(config.cwd, config.outDir);
5098
+ const snapshotDir = path13.resolve(config.cwd, config.outDir);
5098
5099
  const manifestFileMap = /* @__PURE__ */ new Map();
5099
5100
  for (const file of manifest.files) {
5100
5101
  if (file && typeof file.relativePath === "string") {
@@ -5128,7 +5129,7 @@ function validateSnapshot(configInput) {
5128
5129
  }
5129
5130
  let diskHash;
5130
5131
  try {
5131
- diskHash = sha256Hex(fs11.readFileSync(path12.join(config.cwd, diskFile)));
5132
+ diskHash = sha256Hex(fs12.readFileSync(path13.join(config.cwd, diskFile)));
5132
5133
  } catch (err) {
5133
5134
  if (err.code === "ENOENT") {
5134
5135
  drift.missingOnDisk.push(diskFile);
@@ -5152,7 +5153,7 @@ function validateSnapshot(configInput) {
5152
5153
  }
5153
5154
  let statFailure = null;
5154
5155
  try {
5155
- fs11.statSync(confined);
5156
+ fs12.statSync(confined);
5156
5157
  } catch (err) {
5157
5158
  statFailure = err;
5158
5159
  }
@@ -5172,7 +5173,7 @@ function validateSnapshot(configInput) {
5172
5173
  ...Object.values(config.budgets.byLayer)
5173
5174
  );
5174
5175
  const partNames = /* @__PURE__ */ new Set();
5175
- const partsDir = path12.join(snapshotDir, "parts");
5176
+ const partsDir = path13.join(snapshotDir, "parts");
5176
5177
  for (const part of manifest.parts) {
5177
5178
  if (!part || typeof part.filename !== "string") continue;
5178
5179
  partNames.add(part.filename);
@@ -5187,7 +5188,7 @@ function validateSnapshot(configInput) {
5187
5188
  }
5188
5189
  let buffer;
5189
5190
  try {
5190
- buffer = fs11.readFileSync(partPath);
5191
+ buffer = fs12.readFileSync(partPath);
5191
5192
  } catch {
5192
5193
  drift.partIssues.push({ part: part.filename, issue: "missing from snapshot/parts" });
5193
5194
  continue;
@@ -5401,9 +5402,9 @@ function validateSnapshot(configInput) {
5401
5402
  ["full-codebase.md", manifest.artifacts?.fullMarkdown]
5402
5403
  ]) {
5403
5404
  if (!artifact) continue;
5404
- const artifactPath = path12.join(snapshotDir, key);
5405
+ const artifactPath = path13.join(snapshotDir, key);
5405
5406
  try {
5406
- const buffer = fs11.readFileSync(artifactPath);
5407
+ const buffer = fs12.readFileSync(artifactPath);
5407
5408
  if (sha256Hex(buffer) !== artifact.sha256 || buffer.length !== artifact.byteSize) {
5408
5409
  drift.partIssues.push({ part: key, issue: "artifact does not match its recorded digest" });
5409
5410
  }
@@ -5473,12 +5474,168 @@ function validateSnapshot(configInput) {
5473
5474
 
5474
5475
  // src/version.ts
5475
5476
  var GENERATOR_NAME = "codebase-snapshot";
5476
- var GENERATOR_VERSION = "0.9.4";
5477
+ var GENERATOR_VERSION = "0.9.6";
5477
5478
  var LEGACY_GENERATOR_NAMES = ["@ankurhalder/codebase-snapshot"];
5478
5479
  function isOurGeneratorName(name) {
5479
5480
  if (typeof name !== "string") return false;
5480
5481
  return name === GENERATOR_NAME || LEGACY_GENERATOR_NAMES.includes(name);
5481
5482
  }
5483
+ var PACKAGE_LATEST_URL = "https://registry.npmjs.org/codebase-snapshot/latest";
5484
+ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
5485
+ var FAILURE_INTERVAL_MS = 60 * 60 * 1e3;
5486
+ var REQUEST_TIMEOUT_MS = 1200;
5487
+ function versionParts(value) {
5488
+ const core = value.trim().replace(/^v/i, "").split("-")[0];
5489
+ return core.split(".").map((part) => {
5490
+ const parsed = Number(part);
5491
+ return Number.isFinite(parsed) ? parsed : 0;
5492
+ });
5493
+ }
5494
+ function isNewer(candidate, current) {
5495
+ const left = versionParts(candidate);
5496
+ const right = versionParts(current);
5497
+ const length = Math.max(left.length, right.length);
5498
+ for (let index = 0; index < length; index += 1) {
5499
+ const a = left[index] ?? 0;
5500
+ const b = right[index] ?? 0;
5501
+ if (a !== b) return a > b;
5502
+ }
5503
+ return false;
5504
+ }
5505
+ function cacheDirectory(env = process.env, platform = process.platform) {
5506
+ if (platform === "win32") {
5507
+ const base2 = env.LOCALAPPDATA ?? path13.join(os.homedir(), "AppData", "Local");
5508
+ return path13.join(base2, "codebase-snapshot");
5509
+ }
5510
+ if (platform === "darwin") {
5511
+ return path13.join(os.homedir(), "Library", "Caches", "codebase-snapshot");
5512
+ }
5513
+ const base = env.XDG_CACHE_HOME ?? path13.join(os.homedir(), ".cache");
5514
+ return path13.join(base, "codebase-snapshot");
5515
+ }
5516
+ function cacheFilePath(env = process.env) {
5517
+ return path13.join(cacheDirectory(env), "update-check.json");
5518
+ }
5519
+ function shouldCheck(argv, env) {
5520
+ const disabled = ["1", "true", "yes"].includes(
5521
+ String(env.CODEBASE_SNAPSHOT_NO_UPDATE_CHECK ?? "").toLowerCase()
5522
+ );
5523
+ if (disabled) return false;
5524
+ if (env.CI !== void 0 && env.CI !== "" && env.CI !== "false" && env.CI !== "0") return false;
5525
+ const args = argv.map((argument) => argument.toLowerCase());
5526
+ if (args.includes("--no-update-check")) return false;
5527
+ for (const skip of ["mcp", "describe", "skill", "--version", "-v", "--help", "-h"]) {
5528
+ if (args.includes(skip)) return false;
5529
+ }
5530
+ if (args.some((argument) => argument.includes("json"))) return false;
5531
+ return true;
5532
+ }
5533
+ function readCache(file) {
5534
+ let raw;
5535
+ try {
5536
+ raw = fs12.readFileSync(file, "utf8");
5537
+ } catch {
5538
+ return null;
5539
+ }
5540
+ try {
5541
+ const parsed = JSON.parse(raw);
5542
+ if (typeof parsed !== "object" || parsed === null) return null;
5543
+ const candidate = parsed;
5544
+ if (typeof candidate.checkedAt !== "number") return null;
5545
+ const latest = typeof candidate.latest === "string" ? candidate.latest : null;
5546
+ return { checkedAt: candidate.checkedAt, latest };
5547
+ } catch {
5548
+ return null;
5549
+ }
5550
+ }
5551
+ function writeCache(file, entry) {
5552
+ try {
5553
+ fs12.mkdirSync(path13.dirname(file), { recursive: true });
5554
+ fs12.writeFileSync(file, `${JSON.stringify(entry)}
5555
+ `, "utf8");
5556
+ } catch {
5557
+ }
5558
+ }
5559
+ function fetchLatestVersion(url = PACKAGE_LATEST_URL, timeoutMs = REQUEST_TIMEOUT_MS) {
5560
+ return new Promise((resolve5) => {
5561
+ let settled = false;
5562
+ const finish = (value) => {
5563
+ if (settled) return;
5564
+ settled = true;
5565
+ resolve5(value);
5566
+ };
5567
+ const request = https.get(
5568
+ url,
5569
+ {
5570
+ headers: {
5571
+ accept: "application/json",
5572
+ "user-agent": "codebase-snapshot (update check)"
5573
+ }
5574
+ },
5575
+ (response) => {
5576
+ if (response.statusCode !== 200) {
5577
+ response.resume();
5578
+ finish(null);
5579
+ return;
5580
+ }
5581
+ let body = "";
5582
+ response.setEncoding("utf8");
5583
+ response.on("data", (chunk) => {
5584
+ body += chunk;
5585
+ if (body.length > 64 * 1024) {
5586
+ request.destroy();
5587
+ finish(null);
5588
+ }
5589
+ });
5590
+ response.on("end", () => {
5591
+ try {
5592
+ const parsed = JSON.parse(body);
5593
+ finish(typeof parsed.version === "string" ? parsed.version : null);
5594
+ } catch {
5595
+ finish(null);
5596
+ }
5597
+ });
5598
+ }
5599
+ );
5600
+ request.on("error", () => finish(null));
5601
+ request.setTimeout(timeoutMs, () => {
5602
+ request.destroy();
5603
+ finish(null);
5604
+ });
5605
+ });
5606
+ }
5607
+ async function checkForUpdate(options) {
5608
+ if (options.enabled === false) return null;
5609
+ const now = options.now ?? (() => Date.now());
5610
+ const fetchLatest = options.fetchLatest ?? fetchLatestVersion;
5611
+ let latest = null;
5612
+ try {
5613
+ const cached = readCache(options.cacheFile);
5614
+ let needsFetch = cached === null;
5615
+ if (cached) {
5616
+ const age = now() - cached.checkedAt;
5617
+ if (cached.latest === null) {
5618
+ needsFetch = age >= FAILURE_INTERVAL_MS;
5619
+ } else {
5620
+ latest = cached.latest;
5621
+ needsFetch = age >= CHECK_INTERVAL_MS;
5622
+ }
5623
+ }
5624
+ if (needsFetch) {
5625
+ const fetched = await fetchLatest(PACKAGE_LATEST_URL, REQUEST_TIMEOUT_MS);
5626
+ writeCache(options.cacheFile, { checkedAt: now(), latest: fetched });
5627
+ latest = fetched;
5628
+ }
5629
+ } catch {
5630
+ return null;
5631
+ }
5632
+ if (!latest) return null;
5633
+ return isNewer(latest, options.current) ? { current: options.current, latest } : null;
5634
+ }
5635
+ function formatUpdateNotice(notice) {
5636
+ return `\u2191 codebase-snapshot ${notice.latest} is available \u2014 you have ${notice.current}.
5637
+ npm install -g codebase-snapshot`;
5638
+ }
5482
5639
  function describeMatcher(matcher) {
5483
5640
  if (typeof matcher === "string") return matcher;
5484
5641
  if (matcher instanceof RegExp) return String(matcher);
@@ -5488,10 +5645,10 @@ function describeMatcher(matcher) {
5488
5645
  return String(matcher);
5489
5646
  }
5490
5647
  function normalizeTarget(cwd, target) {
5491
- const absolute = path12.resolve(cwd, target);
5492
- const relative7 = path12.relative(cwd, absolute);
5493
- if (relative7.startsWith("..") || path12.isAbsolute(relative7)) return target;
5494
- return relative7.split(path12.sep).join("/");
5648
+ const absolute = path13.resolve(cwd, target);
5649
+ const relative7 = path13.relative(cwd, absolute);
5650
+ if (relative7.startsWith("..") || path13.isAbsolute(relative7)) return target;
5651
+ return relative7.split(path13.sep).join("/");
5495
5652
  }
5496
5653
  function findRuleMatch(rules, relativePath) {
5497
5654
  return rules.find(
@@ -5510,20 +5667,20 @@ function findRecordedAncestor(skipped, relative7, maskedPath2) {
5510
5667
  return nearest;
5511
5668
  }
5512
5669
  function readManifest2(config) {
5513
- const manifestPath = path12.resolve(config.cwd, config.outDir, "manifest.json");
5670
+ const manifestPath = path13.resolve(config.cwd, config.outDir, "manifest.json");
5514
5671
  try {
5515
- return JSON.parse(fs11.readFileSync(manifestPath, "utf8"));
5672
+ return JSON.parse(fs12.readFileSync(manifestPath, "utf8"));
5516
5673
  } catch {
5517
5674
  return null;
5518
5675
  }
5519
5676
  }
5520
5677
  function explainPath(config, target) {
5521
5678
  const relative7 = normalizeTarget(config.cwd, target);
5522
- const absolute = path12.join(config.cwd, relative7);
5679
+ const absolute = path13.join(config.cwd, relative7);
5523
5680
  const maskedPath2 = findSecretInPath(relative7, config.secretRules)?.masked ?? relative7;
5524
5681
  const result = {
5525
5682
  path: maskedPath2,
5526
- exists: fs11.existsSync(absolute),
5683
+ exists: fs12.existsSync(absolute),
5527
5684
  included: false
5528
5685
  };
5529
5686
  const collection = collectFiles(config.cwd, {
@@ -5534,7 +5691,7 @@ function explainPath(config, target) {
5534
5691
  // Same exclusion `generate` applies, so `explain` never says "not-discovered" about a file
5535
5692
  // that is only missing because the walker dropped the tool's own output directory.
5536
5693
  toolOwnedPaths: [config.outDir, config.tmpDir].map(
5537
- (directory) => path12.relative(config.cwd, path12.resolve(config.cwd, directory)).replace(/\\/g, "/")
5694
+ (directory) => path13.relative(config.cwd, path13.resolve(config.cwd, directory)).replace(/\\/g, "/")
5538
5695
  ).filter((relative8) => relative8.length > 0 && !relative8.startsWith(".."))
5539
5696
  });
5540
5697
  if (!collection.files.includes(relative7)) {
@@ -5573,8 +5730,8 @@ function explainPath(config, target) {
5573
5730
  if (layerRule) result.layerMatch = describeMatcher(layerRule.match);
5574
5731
  const kindRule = findRuleMatch(config.kinds, relative7);
5575
5732
  if (kindRule) result.kindMatch = describeMatcher(kindRule.match);
5576
- if (fs11.existsSync(absolute) && fs11.statSync(absolute).isFile()) {
5577
- const buffer = fs11.readFileSync(absolute);
5733
+ if (fs12.existsSync(absolute) && fs12.statSync(absolute).isFile()) {
5734
+ const buffer = fs12.readFileSync(absolute);
5578
5735
  const decoded = decodeText(buffer);
5579
5736
  if (decoded.binary) {
5580
5737
  result.included = false;
@@ -5822,14 +5979,14 @@ function compareManifests(before, after) {
5822
5979
  function loadManifest(target) {
5823
5980
  let isDirectory;
5824
5981
  try {
5825
- isDirectory = fs11.statSync(target).isDirectory();
5982
+ isDirectory = fs12.statSync(target).isDirectory();
5826
5983
  } catch {
5827
5984
  throw new Error(`No snapshot found at ${target}: the path does not exist.`);
5828
5985
  }
5829
- const manifestPath = isDirectory ? path12.join(target, "manifest.json") : target;
5986
+ const manifestPath = isDirectory ? path13.join(target, "manifest.json") : target;
5830
5987
  let raw;
5831
5988
  try {
5832
- raw = fs11.readFileSync(manifestPath, "utf8");
5989
+ raw = fs12.readFileSync(manifestPath, "utf8");
5833
5990
  } catch {
5834
5991
  throw new Error(`Could not read a manifest at ${manifestPath}.`);
5835
5992
  }
@@ -5886,15 +6043,15 @@ function renderDiffText(diff) {
5886
6043
  function appendGitignoreEntries(cwd, entries) {
5887
6044
  const wanted = [...new Set(entries)].filter((entry) => entry.trim().length > 0);
5888
6045
  if (wanted.length === 0) return { added: [], note: null };
5889
- const ignorePath = path12.join(cwd, ".gitignore");
6046
+ const ignorePath = path13.join(cwd, ".gitignore");
5890
6047
  const manual = `Add ${wanted.map((entry) => `"${entry}"`).join(" and ")} to your .gitignore yourself.`;
5891
6048
  let existing = "";
5892
6049
  try {
5893
- if (fs11.existsSync(ignorePath)) {
5894
- if (fs11.statSync(ignorePath).isDirectory()) {
6050
+ if (fs12.existsSync(ignorePath)) {
6051
+ if (fs12.statSync(ignorePath).isDirectory()) {
5895
6052
  return { added: [], note: `${ignorePath} is a directory, so it was not updated. ${manual}` };
5896
6053
  }
5897
- existing = fs11.readFileSync(ignorePath, "utf8");
6054
+ existing = fs12.readFileSync(ignorePath, "utf8");
5898
6055
  }
5899
6056
  } catch (err) {
5900
6057
  return {
@@ -5907,7 +6064,7 @@ function appendGitignoreEntries(cwd, entries) {
5907
6064
  if (added.length === 0) return { added: [], note: null };
5908
6065
  const prefix = existing.length === 0 || existing.endsWith("\n") ? "" : "\n";
5909
6066
  try {
5910
- fs11.writeFileSync(ignorePath, `${existing}${prefix}${added.join("\n")}
6067
+ fs12.writeFileSync(ignorePath, `${existing}${prefix}${added.join("\n")}
5911
6068
  `, "utf8");
5912
6069
  } catch (err) {
5913
6070
  return { added: [], note: `${err.message}. ${manual}` };
@@ -5915,7 +6072,7 @@ function appendGitignoreEntries(cwd, entries) {
5915
6072
  return { added, note: null };
5916
6073
  }
5917
6074
  function gitignorePath(cwd, filePath) {
5918
- return path12.relative(cwd, filePath).split(path12.sep).join("/");
6075
+ return path13.relative(cwd, filePath).split(path13.sep).join("/");
5919
6076
  }
5920
6077
 
5921
6078
  // src/wizard/config-template.ts
@@ -6049,6 +6206,12 @@ var PromptCancelled = class extends Error {
6049
6206
  this.name = "PromptCancelled";
6050
6207
  }
6051
6208
  };
6209
+ var PromptBack = class extends Error {
6210
+ constructor() {
6211
+ super("Prompt back");
6212
+ this.name = "PromptBack";
6213
+ }
6214
+ };
6052
6215
  function defaultIO() {
6053
6216
  return { input: process.stdin, output: process.stdout };
6054
6217
  }
@@ -6072,35 +6235,40 @@ function choiceLine(choice, active) {
6072
6235
  const hint = choice.hint ? ` ${choice.hint}` : "";
6073
6236
  return ` ${marker(active)} ${choice.label}${hint}`;
6074
6237
  }
6075
- function renderSelect(message, choices, index) {
6238
+ function listFooter(base, allowBack) {
6239
+ return allowBack ? `${base} \xB7 \u2190 back` : base;
6240
+ }
6241
+ function renderSelect(message, choices, index, allowBack = false) {
6076
6242
  const lines = [`\u25C6 ${message}`, ""];
6077
6243
  choices.forEach((choice, position) => lines.push(choiceLine(choice, position === index)));
6078
- lines.push("", " \u2191\u2193 move \xB7 enter select");
6244
+ lines.push("", ` ${listFooter("\u2191\u2193 move \xB7 enter select", allowBack)}`);
6079
6245
  return lines.join("\n");
6080
6246
  }
6081
- function renderMultiSelect(message, choices, index, selected) {
6247
+ function renderMultiSelect(message, choices, index, selected, allowBack = false) {
6082
6248
  const lines = [`\u25C6 ${message}`, ""];
6083
6249
  choices.forEach((choice, position) => {
6084
6250
  const box = selected.has(position) ? "\u25FC" : "\u25FB";
6085
6251
  const hint = choice.hint ? ` ${choice.hint}` : "";
6086
6252
  lines.push(` ${marker(position === index)} ${box} ${choice.label}${hint}`);
6087
6253
  });
6088
- lines.push("", " \u2191\u2193 move \xB7 space toggle \xB7 enter confirm");
6254
+ lines.push("", ` ${listFooter("\u2191\u2193 move \xB7 space toggle \xB7 enter confirm", allowBack)}`);
6089
6255
  return lines.join("\n");
6090
6256
  }
6091
- function renderConfirm(message, value) {
6257
+ function renderConfirm(message, value, allowBack = false) {
6258
+ const footer = allowBack ? "\u2190\u2192 or y/n \xB7 enter confirm \xB7 b back" : "\u2190\u2192 or y/n \xB7 enter confirm";
6092
6259
  return [
6093
6260
  `\u25C6 ${message}`,
6094
6261
  "",
6095
6262
  ` ${marker(value)} Yes`,
6096
6263
  ` ${marker(!value)} No`,
6097
6264
  "",
6098
- " \u2190\u2192 or y/n \xB7 enter confirm"
6265
+ ` ${footer}`
6099
6266
  ].join("\n");
6100
6267
  }
6101
- function renderText(message, value, error) {
6268
+ function renderText(message, value, error, allowBack = false) {
6102
6269
  const lines = [`\u25C6 ${message}`, "", ` ${value || "\u258F"}`];
6103
6270
  if (error) lines.push("", ` \u2716 ${error}`);
6271
+ if (allowBack) lines.push("", " enter confirm \xB7 \u2190 back");
6104
6272
  return lines.join("\n");
6105
6273
  }
6106
6274
  function keyReader(input) {
@@ -6149,14 +6317,18 @@ var Frame = class {
6149
6317
  function isCancel(key) {
6150
6318
  return key.ctrl === true && key.name === "c" || key.ctrl === true && key.name === "d";
6151
6319
  }
6320
+ function isListBack(key, allowBack) {
6321
+ return allowBack && (key.name === "left" || key.name === "b");
6322
+ }
6152
6323
  async function select(io, message, choices, options = {}) {
6153
6324
  if (choices.length === 0) throw new Error("select() requires at least one choice.");
6325
+ const allowBack = options.allowBack === true;
6154
6326
  const fallbackIndex = Math.max(
6155
6327
  0,
6156
6328
  choices.findIndex((choice) => choice.value === options.defaultValue)
6157
6329
  );
6158
6330
  if (!isInteractive(io)) {
6159
- io.output.write(`${renderSelect(message, choices, fallbackIndex)}
6331
+ io.output.write(`${renderSelect(message, choices, fallbackIndex, allowBack)}
6160
6332
  `);
6161
6333
  return choices[fallbackIndex].value;
6162
6334
  }
@@ -6165,9 +6337,10 @@ async function select(io, message, choices, options = {}) {
6165
6337
  let index = fallbackIndex;
6166
6338
  try {
6167
6339
  for (; ; ) {
6168
- frame.draw(renderSelect(message, choices, index));
6340
+ frame.draw(renderSelect(message, choices, index, allowBack));
6169
6341
  const key = await reader.next();
6170
6342
  if (isCancel(key)) throw new PromptCancelled();
6343
+ if (isListBack(key, allowBack)) throw new PromptBack();
6171
6344
  if (key.name === "up") index = moveSelection(index, -1, choices.length);
6172
6345
  else if (key.name === "down") index = moveSelection(index, 1, choices.length);
6173
6346
  else if (key.name === "return" || key.name === "enter") {
@@ -6176,18 +6349,22 @@ async function select(io, message, choices, options = {}) {
6176
6349
  } else if (key.name === "j") index = moveSelection(index, 1, choices.length);
6177
6350
  else if (key.name === "k") index = moveSelection(index, -1, choices.length);
6178
6351
  }
6352
+ } catch (error) {
6353
+ frame.erase();
6354
+ throw error;
6179
6355
  } finally {
6180
6356
  reader.close();
6181
6357
  }
6182
6358
  }
6183
6359
  async function multiSelect(io, message, choices, options = {}) {
6360
+ const allowBack = options.allowBack === true;
6184
6361
  const selected = /* @__PURE__ */ new Set();
6185
6362
  choices.forEach((choice, position) => {
6186
6363
  if (options.defaults?.includes(choice.value)) selected.add(position);
6187
6364
  });
6188
6365
  const result = () => choices.filter((_, position) => selected.has(position)).map((choice) => choice.value);
6189
6366
  if (!isInteractive(io)) {
6190
- io.output.write(`${renderMultiSelect(message, choices, 0, selected)}
6367
+ io.output.write(`${renderMultiSelect(message, choices, 0, selected, allowBack)}
6191
6368
  `);
6192
6369
  return result();
6193
6370
  }
@@ -6196,9 +6373,10 @@ async function multiSelect(io, message, choices, options = {}) {
6196
6373
  let index = 0;
6197
6374
  try {
6198
6375
  for (; ; ) {
6199
- frame.draw(renderMultiSelect(message, choices, index, selected));
6376
+ frame.draw(renderMultiSelect(message, choices, index, selected, allowBack));
6200
6377
  const key = await reader.next();
6201
6378
  if (isCancel(key)) throw new PromptCancelled();
6379
+ if (isListBack(key, allowBack)) throw new PromptBack();
6202
6380
  if (key.name === "up") index = moveSelection(index, -1, choices.length);
6203
6381
  else if (key.name === "down") index = moveSelection(index, 1, choices.length);
6204
6382
  else if (key.name === "space") {
@@ -6213,14 +6391,18 @@ async function multiSelect(io, message, choices, options = {}) {
6213
6391
  return result();
6214
6392
  }
6215
6393
  }
6394
+ } catch (error) {
6395
+ frame.erase();
6396
+ throw error;
6216
6397
  } finally {
6217
6398
  reader.close();
6218
6399
  }
6219
6400
  }
6220
6401
  async function confirm(io, message, options = {}) {
6402
+ const allowBack = options.allowBack === true;
6221
6403
  let value = options.defaultValue ?? true;
6222
6404
  if (!isInteractive(io)) {
6223
- io.output.write(`${renderConfirm(message, value)}
6405
+ io.output.write(`${renderConfirm(message, value, allowBack)}
6224
6406
  `);
6225
6407
  return value;
6226
6408
  }
@@ -6228,9 +6410,10 @@ async function confirm(io, message, options = {}) {
6228
6410
  const reader = keyReader(io.input);
6229
6411
  try {
6230
6412
  for (; ; ) {
6231
- frame.draw(renderConfirm(message, value));
6413
+ frame.draw(renderConfirm(message, value, allowBack));
6232
6414
  const key = await reader.next();
6233
6415
  if (isCancel(key)) throw new PromptCancelled();
6416
+ if (allowBack && key.name === "b") throw new PromptBack();
6234
6417
  if (key.name === "up" || key.name === "left") value = true;
6235
6418
  else if (key.name === "down" || key.name === "right") value = false;
6236
6419
  else if (key.name === "y") value = true;
@@ -6240,14 +6423,18 @@ async function confirm(io, message, options = {}) {
6240
6423
  return value;
6241
6424
  }
6242
6425
  }
6426
+ } catch (error) {
6427
+ frame.erase();
6428
+ throw error;
6243
6429
  } finally {
6244
6430
  reader.close();
6245
6431
  }
6246
6432
  }
6247
6433
  async function text(io, message, options = {}) {
6434
+ const allowBack = options.allowBack === true;
6248
6435
  const fallback = options.defaultValue ?? "";
6249
6436
  if (!isInteractive(io)) {
6250
- io.output.write(`${renderText(message, fallback)}
6437
+ io.output.write(`${renderText(message, fallback, void 0, allowBack)}
6251
6438
  `);
6252
6439
  return fallback;
6253
6440
  }
@@ -6257,9 +6444,10 @@ async function text(io, message, options = {}) {
6257
6444
  let error;
6258
6445
  try {
6259
6446
  for (; ; ) {
6260
- frame.draw(renderText(message, value, error));
6447
+ frame.draw(renderText(message, value, error, allowBack));
6261
6448
  const key = await reader.next();
6262
6449
  if (isCancel(key)) throw new PromptCancelled();
6450
+ if (allowBack && key.name === "left") throw new PromptBack();
6263
6451
  error = void 0;
6264
6452
  if (key.name === "return" || key.name === "enter") {
6265
6453
  const problem = options.validate ? options.validate(value) : null;
@@ -6280,6 +6468,9 @@ async function text(io, message, options = {}) {
6280
6468
  }
6281
6469
  if (_isPrintable(key)) value += _keyText(key);
6282
6470
  }
6471
+ } catch (error_) {
6472
+ frame.erase();
6473
+ throw error_;
6283
6474
  } finally {
6284
6475
  reader.close();
6285
6476
  }
@@ -6303,10 +6494,10 @@ var CONFIG_CANDIDATES = [
6303
6494
  ];
6304
6495
  function chooseConfigFileName(cwd) {
6305
6496
  if (!supportsTypeScriptImports()) return "snapshot.config.mjs";
6306
- const pkgPath = path12.join(cwd, "package.json");
6307
- if (!fs11.existsSync(pkgPath)) return "snapshot.config.mjs";
6497
+ const pkgPath = path13.join(cwd, "package.json");
6498
+ if (!fs12.existsSync(pkgPath)) return "snapshot.config.mjs";
6308
6499
  try {
6309
- const parsed = JSON.parse(fs11.readFileSync(pkgPath, "utf8"));
6500
+ const parsed = JSON.parse(fs12.readFileSync(pkgPath, "utf8"));
6310
6501
  return parsed.type === "module" ? "snapshot.config.ts" : "snapshot.config.mjs";
6311
6502
  } catch {
6312
6503
  return "snapshot.config.mjs";
@@ -6320,7 +6511,7 @@ var SIZE_CHOICES = [
6320
6511
  ];
6321
6512
  function packageJsonHasConfig(cwd) {
6322
6513
  try {
6323
- const parsed = JSON.parse(fs11.readFileSync(path12.join(cwd, "package.json"), "utf8"));
6514
+ const parsed = JSON.parse(fs12.readFileSync(path13.join(cwd, "package.json"), "utf8"));
6324
6515
  return typeof parsed.snapshot === "object" && parsed.snapshot !== null && !Array.isArray(parsed.snapshot);
6325
6516
  } catch {
6326
6517
  return false;
@@ -6341,7 +6532,7 @@ function artifactAnswers(options) {
6341
6532
  }
6342
6533
  function topLevelDirs(cwd) {
6343
6534
  try {
6344
- return fs11.readdirSync(cwd, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules").map((entry) => entry.name).sort();
6535
+ return fs12.readdirSync(cwd, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules").map((entry) => entry.name).sort();
6345
6536
  } catch {
6346
6537
  return [];
6347
6538
  }
@@ -6354,7 +6545,7 @@ function describeJsonValue(value) {
6354
6545
  }
6355
6546
  function writeFileOrExplain(target, content) {
6356
6547
  try {
6357
- fs11.writeFileSync(target, content, "utf8");
6548
+ fs12.writeFileSync(target, content, "utf8");
6358
6549
  } catch (err) {
6359
6550
  const code = err.code;
6360
6551
  const reason = code === "EACCES" || code === "EPERM" || code === "EROFS" ? `permission denied (${code})` : code === "EISDIR" ? "it is a directory" : `${err.message}`;
@@ -6365,7 +6556,7 @@ function canWriteModuleConfig(name, cwd) {
6365
6556
  if (name.endsWith(".mjs") || name.endsWith(".ts")) return true;
6366
6557
  if (!name.endsWith(".js")) return false;
6367
6558
  try {
6368
- const parsed = JSON.parse(fs11.readFileSync(path12.join(cwd, "package.json"), "utf8"));
6559
+ const parsed = JSON.parse(fs12.readFileSync(path13.join(cwd, "package.json"), "utf8"));
6369
6560
  return parsed.type === "module";
6370
6561
  } catch {
6371
6562
  return false;
@@ -6400,19 +6591,19 @@ function serializePackageJson(raw, value) {
6400
6591
  return `${text2}${raw.endsWith("\n") ? crlf ? "\r\n" : "\n" : ""}`;
6401
6592
  }
6402
6593
  function updatePackageJson(cwd, notes) {
6403
- const packagePath = path12.join(cwd, "package.json");
6594
+ const packagePath = path13.join(cwd, "package.json");
6404
6595
  const unchanged = {
6405
6596
  scripts: [],
6406
6597
  dependency: { name: GENERATOR_NAME, range: null, added: false }
6407
6598
  };
6408
- if (!fs11.existsSync(packagePath)) {
6599
+ if (!fs12.existsSync(packagePath)) {
6409
6600
  notes.push("No package.json found, so npm scripts and the devDependency were not added.");
6410
6601
  return unchanged;
6411
6602
  }
6412
6603
  let raw;
6413
6604
  let parsed;
6414
6605
  try {
6415
- raw = fs11.readFileSync(packagePath, "utf8");
6606
+ raw = fs12.readFileSync(packagePath, "utf8");
6416
6607
  parsed = JSON.parse(raw);
6417
6608
  } catch {
6418
6609
  notes.push("Could not parse package.json; npm scripts and the devDependency were not added.");
@@ -6536,98 +6727,108 @@ async function runInit(options) {
6536
6727
  { value: "walk", label: "Go through each setting", hint: "every question starts on its default" },
6537
6728
  { value: "choose", label: "Pick a different preset", hint: "everything else stays at the defaults" }
6538
6729
  ];
6539
- const pace = await select(io, "How should I set this up?", paceChoices, {
6540
- defaultValue: fallback ? "choose" : "recommended"
6541
- });
6542
- if (pace === "choose") {
6543
- answers.preset = await select(
6544
- io,
6545
- "What kind of project is this?",
6546
- listPresetNames().map(
6547
- (name) => resolvePresetChoice(fallback ? null : detected.presetName, name)
6548
- ),
6549
- { defaultValue: answers.preset }
6550
- );
6551
- const chosen = detectPreset(options.cwd, answers.preset);
6552
- answers.preset = chosen.presetName;
6553
- reason = null;
6554
- fallback = false;
6555
- }
6556
- if (pace === "walk") {
6557
- const scope = await select(
6558
- io,
6559
- "What should go into the snapshot?",
6560
- [
6561
- { value: "all", label: "Everything the scanner finds", hint: "recommended \xB7 respects .gitignore" },
6562
- { value: "folders", label: "Only specific folders\u2026" },
6563
- { value: "no-tests", label: "Everything, but skip tests" },
6564
- { value: "custom", label: "Let me write glob patterns" }
6565
- ],
6566
- { defaultValue: "all" }
6567
- );
6568
- if (scope === "folders") {
6569
- const dirs = topLevelDirs(options.cwd).slice(0, 40);
6570
- if (dirs.length === 0) {
6571
- notes.push("No top-level directories found; the snapshot will include everything.");
6572
- } else {
6573
- const chosen = await multiSelect(
6574
- io,
6575
- "Select folders",
6576
- dirs.map((name) => ({ value: name, label: `${name}/` })),
6577
- { defaults: dirs }
6578
- );
6579
- answers.include = chosen.map((name) => `${name}/**`);
6730
+ const baseInclude = [...answers.include];
6731
+ const baseExclude = [...answers.excludePatterns];
6732
+ let lastScope = "all";
6733
+ const artifactChoices = [
6734
+ { value: "readme", label: "README.md", hint: "orientation page" },
6735
+ { value: "manifest", label: "manifest.json", hint: "required by validate and report" },
6736
+ { value: "parts", label: "parts/", hint: "the code payload" },
6737
+ { value: "navigation", label: "reports/navigation.md", hint: "file \u2192 part index" },
6738
+ { value: "projectTree", label: "reports/project-tree.md", hint: "ASCII tree" },
6739
+ { value: "audit", label: "reports/audit.md", hint: "security and health findings" },
6740
+ { value: "monolith", label: "full-codebase.json + .md", hint: "roughly doubles output" }
6741
+ ];
6742
+ const scopeStep = async () => {
6743
+ for (; ; ) {
6744
+ const scope = await select(
6745
+ io,
6746
+ "What should go into the snapshot?",
6747
+ [
6748
+ { value: "all", label: "Everything the scanner finds", hint: "recommended \xB7 respects .gitignore" },
6749
+ { value: "folders", label: "Only specific folders\u2026" },
6750
+ { value: "no-tests", label: "Everything, but skip tests" },
6751
+ { value: "custom", label: "Let me write glob patterns" }
6752
+ ],
6753
+ { defaultValue: lastScope, allowBack: true }
6754
+ );
6755
+ lastScope = scope;
6756
+ answers.include = [...baseInclude];
6757
+ answers.excludePatterns = [...baseExclude];
6758
+ try {
6759
+ if (scope === "folders") {
6760
+ const dirs = topLevelDirs(options.cwd).slice(0, 40);
6761
+ if (dirs.length === 0) {
6762
+ notes.push("No top-level directories found; the snapshot will include everything.");
6763
+ } else {
6764
+ const chosen = await multiSelect(
6765
+ io,
6766
+ "Select folders",
6767
+ dirs.map((name) => ({ value: name, label: `${name}/` })),
6768
+ { defaults: dirs, allowBack: true }
6769
+ );
6770
+ answers.include = chosen.map((name) => `${name}/**`);
6771
+ }
6772
+ } else if (scope === "no-tests") {
6773
+ answers.excludePatterns = [...baseExclude, "**/*.test.*", "**/*.spec.*", "tests", "test"];
6774
+ } else if (scope === "custom") {
6775
+ const raw = await text(io, "Glob patterns to include (comma separated)", {
6776
+ defaultValue: baseInclude.join(", "),
6777
+ allowBack: true
6778
+ });
6779
+ answers.include = raw.split(",").map((value) => value.trim()).filter(Boolean);
6780
+ }
6781
+ return;
6782
+ } catch (error) {
6783
+ if (error instanceof PromptBack) continue;
6784
+ throw error;
6580
6785
  }
6581
- } else if (scope === "no-tests") {
6582
- answers.excludePatterns = [
6583
- ...answers.excludePatterns,
6584
- "**/*.test.*",
6585
- "**/*.spec.*",
6586
- "tests",
6587
- "test"
6588
- ];
6589
- } else if (scope === "custom") {
6590
- const raw = await text(io, "Glob patterns to include (comma separated)", {
6591
- defaultValue: ""
6592
- });
6593
- answers.include = raw.split(",").map((value) => value.trim()).filter(Boolean);
6594
6786
  }
6595
- const currentBudget = String(answers.maxPartBytes);
6596
- const sizeChoice = await select(io, "How large should each part be?", SIZE_CHOICES, {
6597
- defaultValue: SIZE_CHOICES.some((choice) => choice.value === currentBudget) ? currentBudget : "120k"
6598
- });
6599
- if (sizeChoice === "custom") {
6600
- const raw = await text(io, "Part size (e.g. 150k, 1.5mb, 900000)", {
6601
- defaultValue: String(answers.maxPartBytes),
6602
- validate: (value) => parseByteSize(value) === void 0 ? "Not a valid size." : null
6787
+ };
6788
+ const sizeStep = async () => {
6789
+ for (; ; ) {
6790
+ const currentBudget = String(answers.maxPartBytes);
6791
+ const sizeChoice = await select(io, "How large should each part be?", SIZE_CHOICES, {
6792
+ defaultValue: SIZE_CHOICES.some((choice) => choice.value === currentBudget) ? currentBudget : "custom",
6793
+ allowBack: true
6603
6794
  });
6604
- answers.maxPartBytes = parseByteSize(raw) ?? answers.maxPartBytes;
6605
- } else {
6606
- answers.maxPartBytes = sizeChoice;
6795
+ if (sizeChoice !== "custom") {
6796
+ answers.maxPartBytes = sizeChoice;
6797
+ return;
6798
+ }
6799
+ try {
6800
+ const raw = await text(io, "Part size (e.g. 150k, 1.5mb, 900000)", {
6801
+ defaultValue: currentBudget,
6802
+ validate: (value) => parseByteSize(value) === void 0 ? "Not a valid size." : null,
6803
+ allowBack: true
6804
+ });
6805
+ answers.maxPartBytes = parseByteSize(raw) ?? answers.maxPartBytes;
6806
+ return;
6807
+ } catch (error) {
6808
+ if (error instanceof PromptBack) continue;
6809
+ throw error;
6810
+ }
6607
6811
  }
6608
- const artifactChoices = [
6609
- { value: "readme", label: "README.md", hint: "orientation page" },
6610
- { value: "manifest", label: "manifest.json", hint: "required by validate and report" },
6611
- { value: "parts", label: "parts/", hint: "the code payload" },
6612
- { value: "navigation", label: "reports/navigation.md", hint: "file \u2192 part index" },
6613
- { value: "projectTree", label: "reports/project-tree.md", hint: "ASCII tree" },
6614
- { value: "audit", label: "reports/audit.md", hint: "security and health findings" },
6615
- { value: "monolith", label: "full-codebase.json + .md", hint: "roughly doubles output" }
6616
- ];
6617
- const presetEnabled = ARTIFACT_NAMES.filter((name) => answers.artifacts[name]);
6812
+ };
6813
+ const artifactsStep = async () => {
6814
+ const enabled = ARTIFACT_NAMES.filter((name) => answers.artifacts[name]);
6618
6815
  const selectedArtifacts = await multiSelect(
6619
6816
  io,
6620
6817
  "Which artifacts should be generated?",
6621
6818
  artifactChoices,
6622
- { defaults: presetEnabled }
6819
+ { defaults: enabled, allowBack: true }
6623
6820
  );
6624
6821
  for (const name of ARTIFACT_NAMES) answers.artifacts[name] = selectedArtifacts.includes(name);
6625
- const enabledCount = ARTIFACT_NAMES.filter((name) => answers.artifacts[name]).length;
6822
+ };
6823
+ const credentialsStep = async () => {
6626
6824
  answers.includeSensitiveFiles = await confirm(
6627
6825
  io,
6628
- "Include credential files (.env, *.pem, .npmrc, .ssh/)?",
6629
- { defaultValue: false }
6826
+ "Include credential files (.env, *.pem, *.npmrc, *.ssh/)?",
6827
+ { defaultValue: answers.includeSensitiveFiles, allowBack: true }
6630
6828
  );
6829
+ };
6830
+ const reviewStep = async () => {
6831
+ const enabledCount = ARTIFACT_NAMES.filter((name) => answers.artifacts[name]).length;
6631
6832
  io.output.write("\n Review\n\n");
6632
6833
  io.output.write(` project ${answers.preset}
6633
6834
  `);
@@ -6642,14 +6843,59 @@ async function runInit(options) {
6642
6843
  `);
6643
6844
  io.output.write(" Will write snapshot.config with your answers, plus every other setting\n");
6644
6845
  io.output.write(" at its default \u2014 so nothing is hidden behind the docs.\n\n");
6645
- const proceed = await confirm(io, "Write this and continue?", { defaultValue: true });
6646
- if (!proceed) throw new PromptCancelled();
6846
+ const proceed = await confirm(io, "Write this and continue?", {
6847
+ defaultValue: true,
6848
+ allowBack: true
6849
+ });
6850
+ if (!proceed) throw new PromptBack();
6851
+ };
6852
+ const walk = async () => {
6853
+ const steps = [scopeStep, sizeStep, artifactsStep, credentialsStep, reviewStep];
6854
+ let index = 0;
6855
+ while (index < steps.length) {
6856
+ try {
6857
+ await steps[index]();
6858
+ index += 1;
6859
+ } catch (error) {
6860
+ if (!(error instanceof PromptBack)) throw error;
6861
+ if (index === 0) return false;
6862
+ index -= 1;
6863
+ io.output.write("\n");
6864
+ }
6865
+ }
6866
+ return true;
6867
+ };
6868
+ for (; ; ) {
6869
+ const pace = await select(io, "How should I set this up?", paceChoices, {
6870
+ defaultValue: fallback ? "choose" : "recommended"
6871
+ });
6872
+ if (pace === "choose") {
6873
+ try {
6874
+ answers.preset = await select(
6875
+ io,
6876
+ "What kind of project is this?",
6877
+ listPresetNames().map(
6878
+ (name) => resolvePresetChoice(fallback ? null : detected.presetName, name)
6879
+ ),
6880
+ { defaultValue: answers.preset, allowBack: true }
6881
+ );
6882
+ } catch (error) {
6883
+ if (error instanceof PromptBack) continue;
6884
+ throw error;
6885
+ }
6886
+ const chosen = detectPreset(options.cwd, answers.preset);
6887
+ answers.preset = chosen.presetName;
6888
+ reason = null;
6889
+ fallback = false;
6890
+ }
6891
+ if (pace === "walk" && !await walk()) continue;
6892
+ break;
6647
6893
  }
6648
6894
  }
6649
6895
  const configText = renderConfig(answers);
6650
6896
  const preferredName = chooseConfigFileName(options.cwd);
6651
6897
  const presentConfigs = CONFIG_CANDIDATES.filter(
6652
- (name) => fs11.existsSync(path12.join(options.cwd, name))
6898
+ (name) => fs12.existsSync(path13.join(options.cwd, name))
6653
6899
  );
6654
6900
  const present = presentConfigs[0] ?? null;
6655
6901
  if (presentConfigs.length > 1) {
@@ -6658,7 +6904,7 @@ async function runInit(options) {
6658
6904
  );
6659
6905
  }
6660
6906
  const configName = present !== null && options.force ? present : preferredName;
6661
- const configPath = path12.join(options.cwd, configName);
6907
+ const configPath = path13.join(options.cwd, configName);
6662
6908
  const reused = present !== null && options.force !== true && options.reuseConfig === true;
6663
6909
  if (reused) notes.push(`Kept the existing ${present} instead of writing a new one.`);
6664
6910
  if (options.dryRun) {
@@ -6691,7 +6937,7 @@ async function runInit(options) {
6691
6937
  'package.json already defines a "snapshot" config. Remove that key, or re-run with --force to write a config file that takes precedence over it.'
6692
6938
  );
6693
6939
  }
6694
- if (fs11.existsSync(configPath) && !options.force && !reused) {
6940
+ if (fs12.existsSync(configPath) && !options.force && !reused) {
6695
6941
  throw new Error(`${configName} already exists. Re-run with --force to replace it.`);
6696
6942
  }
6697
6943
  if (!reused) writeFileOrExplain(configPath, configText);
@@ -6713,9 +6959,9 @@ async function runInit(options) {
6713
6959
  };
6714
6960
  }
6715
6961
  function describeTarget(cwd) {
6716
- const relative7 = path12.relative(process.cwd(), cwd);
6962
+ const relative7 = path13.relative(process.cwd(), cwd);
6717
6963
  if (relative7 === "") return "this directory";
6718
- if (relative7.startsWith("..") || path12.isAbsolute(relative7)) return cwd;
6964
+ if (relative7.startsWith("..") || path13.isAbsolute(relative7)) return cwd;
6719
6965
  return relative7;
6720
6966
  }
6721
6967
  function firstRunMessage(reason, cwd) {
@@ -6739,7 +6985,7 @@ function planFirstRun(facts) {
6739
6985
  var NOT_CONTENT = /* @__PURE__ */ new Set([".git", ".hg", ".svn", ".bzr", ".DS_Store", "Thumbs.db"]);
6740
6986
  function isEffectivelyEmpty(cwd) {
6741
6987
  try {
6742
- return fs11.readdirSync(cwd).every((entry) => NOT_CONTENT.has(entry));
6988
+ return fs12.readdirSync(cwd).every((entry) => NOT_CONTENT.has(entry));
6743
6989
  } catch {
6744
6990
  return false;
6745
6991
  }
@@ -6747,7 +6993,7 @@ function isEffectivelyEmpty(cwd) {
6747
6993
  function hasPriorSnapshot(cwd, outDir) {
6748
6994
  let parsed;
6749
6995
  try {
6750
- parsed = JSON.parse(fs11.readFileSync(path12.join(cwd, outDir, ".codebase-snapshot"), "utf8"));
6996
+ parsed = JSON.parse(fs12.readFileSync(path13.join(cwd, outDir, ".codebase-snapshot"), "utf8"));
6751
6997
  } catch {
6752
6998
  return false;
6753
6999
  }
@@ -6835,13 +7081,13 @@ function buildImportResolver(files) {
6835
7081
  const relativePath = file.relativePath;
6836
7082
  remember(byPath, relativePath, relativePath);
6837
7083
  remember(byPathFolded, relativePath.toLowerCase(), relativePath);
6838
- const extension = path12.posix.extname(relativePath);
7084
+ const extension = path13.posix.extname(relativePath);
6839
7085
  if (!SOURCE_EXTENSIONS.has(extension)) continue;
6840
7086
  const stem = relativePath.slice(0, -extension.length);
6841
7087
  remember(byStem, stem, relativePath);
6842
7088
  remember(byStemFolded, stem.toLowerCase(), relativePath);
6843
- if (path12.posix.basename(stem) === "index") {
6844
- const directory = path12.posix.dirname(stem);
7089
+ if (path13.posix.basename(stem) === "index") {
7090
+ const directory = path13.posix.dirname(stem);
6845
7091
  remember(byStem, directory, relativePath);
6846
7092
  remember(byStemFolded, directory.toLowerCase(), relativePath);
6847
7093
  }
@@ -6850,8 +7096,8 @@ function buildImportResolver(files) {
6850
7096
  }
6851
7097
  function resolveSpecifier(fromFile, specifier, resolver) {
6852
7098
  if (!RELATIVE_SPECIFIER.test(specifier)) return null;
6853
- const joined = path12.posix.normalize(
6854
- path12.posix.join(path12.posix.dirname(fromFile), specifier)
7099
+ const joined = path13.posix.normalize(
7100
+ path13.posix.join(path13.posix.dirname(fromFile), specifier)
6855
7101
  );
6856
7102
  const exact = (key) => resolver.byPath.get(key) ?? resolver.byPathFolded.get(key.toLowerCase()) ?? null;
6857
7103
  const direct = exact(joined);
@@ -6944,11 +7190,11 @@ function verifyInMemory(files, parts, maxPartBytes) {
6944
7190
  return errors;
6945
7191
  }
6946
7192
  function resolveSafeOutputDirs(config) {
6947
- const cwd = path12.resolve(config.cwd);
6948
- const outDir = path12.resolve(cwd, config.outDir);
6949
- const tmpDir = path12.resolve(cwd, config.tmpDir);
6950
- const root = path12.parse(cwd).root;
6951
- const contains = (parent, child) => child === parent || child.startsWith(`${parent}${path12.sep}`);
7193
+ const cwd = path13.resolve(config.cwd);
7194
+ const outDir = path13.resolve(cwd, config.outDir);
7195
+ const tmpDir = path13.resolve(cwd, config.tmpDir);
7196
+ const root = path13.parse(cwd).root;
7197
+ const contains = (parent, child) => child === parent || child.startsWith(`${parent}${path13.sep}`);
6952
7198
  const reject = (reason) => {
6953
7199
  throw new Error(
6954
7200
  `Refusing to generate: ${reason}. outDir=${outDir} tmpDir=${tmpDir} cwd=${cwd}`
@@ -7004,14 +7250,14 @@ function listEntries(dir) {
7004
7250
  const walk = (absolute, prefix) => {
7005
7251
  let children;
7006
7252
  try {
7007
- children = fs11.readdirSync(absolute, { withFileTypes: true });
7253
+ children = fs12.readdirSync(absolute, { withFileTypes: true });
7008
7254
  } catch {
7009
7255
  return;
7010
7256
  }
7011
7257
  for (const child of children) {
7012
7258
  const relative7 = prefix === "" ? child.name : `${prefix}/${child.name}`;
7013
7259
  entries.push(relative7);
7014
- if (child.isDirectory()) walk(path12.join(absolute, child.name), relative7);
7260
+ if (child.isDirectory()) walk(path13.join(absolute, child.name), relative7);
7015
7261
  }
7016
7262
  };
7017
7263
  walk(dir, "");
@@ -7028,28 +7274,28 @@ function markerPayload(dir, state, id, createdAt) {
7028
7274
  pid: process.pid,
7029
7275
  entries: listEntries(dir)
7030
7276
  };
7031
- const manifestPath = path12.join(dir, "manifest.json");
7032
- if (fs11.existsSync(manifestPath)) {
7033
- marker2.manifestSha256 = sha256Hex2(fs11.readFileSync(manifestPath));
7277
+ const manifestPath = path13.join(dir, "manifest.json");
7278
+ if (fs12.existsSync(manifestPath)) {
7279
+ marker2.manifestSha256 = sha256Hex2(fs12.readFileSync(manifestPath));
7034
7280
  }
7035
7281
  return marker2;
7036
7282
  }
7037
7283
  function writeOwnershipMarker(dir, marker2) {
7038
- fs11.writeFileSync(
7039
- path12.join(dir, OWNERSHIP_MARKER),
7284
+ fs12.writeFileSync(
7285
+ path13.join(dir, OWNERSHIP_MARKER),
7040
7286
  `${JSON.stringify(marker2, null, 2)}
7041
7287
  `,
7042
7288
  "utf8"
7043
7289
  );
7044
7290
  }
7045
7291
  function readOwnershipMarker(dir) {
7046
- const markerPath = path12.join(dir, OWNERSHIP_MARKER);
7047
- if (!fs11.existsSync(markerPath)) {
7292
+ const markerPath = path13.join(dir, OWNERSHIP_MARKER);
7293
+ if (!fs12.existsSync(markerPath)) {
7048
7294
  return { marker: null, problem: "it holds no .codebase-snapshot marker" };
7049
7295
  }
7050
7296
  let raw;
7051
7297
  try {
7052
- raw = fs11.readFileSync(markerPath, "utf8");
7298
+ raw = fs12.readFileSync(markerPath, "utf8");
7053
7299
  } catch {
7054
7300
  return { marker: null, problem: "its .codebase-snapshot marker could not be read" };
7055
7301
  }
@@ -7117,11 +7363,11 @@ function assessSnapshotDirectory(dir) {
7117
7363
  marker: marker2
7118
7364
  };
7119
7365
  }
7120
- const manifestPath = path12.join(dir, "manifest.json");
7121
- if (fs11.existsSync(manifestPath)) {
7366
+ const manifestPath = path13.join(dir, "manifest.json");
7367
+ if (fs12.existsSync(manifestPath)) {
7122
7368
  let raw;
7123
7369
  try {
7124
- raw = fs11.readFileSync(manifestPath, "utf8");
7370
+ raw = fs12.readFileSync(manifestPath, "utf8");
7125
7371
  } catch {
7126
7372
  return {
7127
7373
  owned: false,
@@ -7203,13 +7449,13 @@ function containsNoFiles(dir) {
7203
7449
  const current = pending.pop();
7204
7450
  let entries;
7205
7451
  try {
7206
- entries = fs11.readdirSync(current, { withFileTypes: true });
7452
+ entries = fs12.readdirSync(current, { withFileTypes: true });
7207
7453
  } catch {
7208
7454
  return false;
7209
7455
  }
7210
7456
  for (const entry of entries) {
7211
7457
  if (entry.isDirectory()) {
7212
- pending.push(path12.join(current, entry.name));
7458
+ pending.push(path13.join(current, entry.name));
7213
7459
  } else if (!IGNORABLE_ENTRIES.has(entry.name)) {
7214
7460
  return false;
7215
7461
  }
@@ -7218,13 +7464,13 @@ function containsNoFiles(dir) {
7218
7464
  return true;
7219
7465
  }
7220
7466
  function assertReplaceable(target, label, secretRules) {
7221
- if (!fs11.existsSync(target)) return;
7222
- if (!fs11.statSync(target).isDirectory()) {
7467
+ if (!fs12.existsSync(target)) return;
7468
+ if (!fs12.statSync(target).isDirectory()) {
7223
7469
  throw new Error(
7224
7470
  `Refusing to write into ${label} ${target}: it exists but is not a directory.`
7225
7471
  );
7226
7472
  }
7227
- const entries = fs11.readdirSync(target);
7473
+ const entries = fs12.readdirSync(target);
7228
7474
  if (entries.length === 0) return;
7229
7475
  if (entries.every((name) => IGNORABLE_ENTRIES.has(name))) return;
7230
7476
  if (containsNoFiles(target)) return;
@@ -7244,18 +7490,18 @@ function assertReplaceable(target, label, secretRules) {
7244
7490
  );
7245
7491
  }
7246
7492
  function assertStagingRootUsable(tmpDir, secretRules) {
7247
- if (!fs11.existsSync(tmpDir)) return;
7248
- if (!fs11.statSync(tmpDir).isDirectory()) {
7493
+ if (!fs12.existsSync(tmpDir)) return;
7494
+ if (!fs12.statSync(tmpDir).isDirectory()) {
7249
7495
  throw new Error(`Refusing to write into tmpDir ${tmpDir}: it exists but is not a directory.`);
7250
7496
  }
7251
- const entries = fs11.readdirSync(tmpDir);
7497
+ const entries = fs12.readdirSync(tmpDir);
7252
7498
  if (entries.length === 0) return;
7253
7499
  const foreign = entries.filter((name) => {
7254
- const full = path12.join(tmpDir, name);
7500
+ const full = path13.join(tmpDir, name);
7255
7501
  if (!name.startsWith(RUN_DIR_PREFIX)) return true;
7256
7502
  let stats;
7257
7503
  try {
7258
- stats = fs11.statSync(full);
7504
+ stats = fs12.statSync(full);
7259
7505
  } catch {
7260
7506
  return true;
7261
7507
  }
@@ -7263,7 +7509,7 @@ function assertStagingRootUsable(tmpDir, secretRules) {
7263
7509
  const { marker: marker2 } = readOwnershipMarker(full);
7264
7510
  if (marker2) return false;
7265
7511
  try {
7266
- return fs11.readdirSync(full).length > 0;
7512
+ return fs12.readdirSync(full).length > 0;
7267
7513
  } catch {
7268
7514
  return true;
7269
7515
  }
@@ -7278,13 +7524,13 @@ function assertStagingRootUsable(tmpDir, secretRules) {
7278
7524
  function cleanStaleRunDirs(tmpDir) {
7279
7525
  let entries;
7280
7526
  try {
7281
- entries = fs11.readdirSync(tmpDir);
7527
+ entries = fs12.readdirSync(tmpDir);
7282
7528
  } catch {
7283
7529
  return;
7284
7530
  }
7285
7531
  for (const name of entries) {
7286
7532
  if (!name.startsWith(RUN_DIR_PREFIX)) continue;
7287
- const full = path12.join(tmpDir, name);
7533
+ const full = path13.join(tmpDir, name);
7288
7534
  const { marker: marker2 } = readOwnershipMarker(full);
7289
7535
  if (marker2) {
7290
7536
  const created = Date.parse(marker2.createdAt);
@@ -7292,33 +7538,33 @@ function cleanStaleRunDirs(tmpDir) {
7292
7538
  const abandoned = typeof marker2.pid === "number" && !isProcessAlive(marker2.pid);
7293
7539
  if (aged || abandoned) {
7294
7540
  try {
7295
- fs11.rmSync(full, { recursive: true, force: true });
7541
+ fs12.rmSync(full, { recursive: true, force: true });
7296
7542
  } catch {
7297
7543
  }
7298
7544
  }
7299
7545
  continue;
7300
7546
  }
7301
7547
  try {
7302
- if (fs11.readdirSync(full).length === 0) fs11.rmSync(full, { recursive: true, force: true });
7548
+ if (fs12.readdirSync(full).length === 0) fs12.rmSync(full, { recursive: true, force: true });
7303
7549
  } catch {
7304
7550
  }
7305
7551
  }
7306
7552
  }
7307
7553
  function removeIfEmpty(dir) {
7308
7554
  try {
7309
- if (fs11.readdirSync(dir).length === 0) fs11.rmSync(dir, { recursive: true, force: true });
7555
+ if (fs12.readdirSync(dir).length === 0) fs12.rmSync(dir, { recursive: true, force: true });
7310
7556
  } catch {
7311
7557
  }
7312
7558
  }
7313
7559
  function ensureParentDirectory(target, label) {
7314
- const parent = path12.dirname(target);
7315
- if (fs11.existsSync(parent) && !fs11.statSync(parent).isDirectory()) {
7560
+ const parent = path13.dirname(target);
7561
+ if (fs12.existsSync(parent) && !fs12.statSync(parent).isDirectory()) {
7316
7562
  throw new Error(
7317
7563
  `Refusing to create ${label} ${target}: ${parent} exists but is not a directory.`
7318
7564
  );
7319
7565
  }
7320
7566
  try {
7321
- fs11.mkdirSync(parent, { recursive: true });
7567
+ fs12.mkdirSync(parent, { recursive: true });
7322
7568
  } catch (err) {
7323
7569
  throw new Error(
7324
7570
  `Refusing to create ${label} ${target}: its parent ${parent} could not be created (${err.message}).`
@@ -7327,7 +7573,7 @@ function ensureParentDirectory(target, label) {
7327
7573
  }
7328
7574
  function acquireRunLock(stagingRoot) {
7329
7575
  const key = lockKeyFor(stagingRoot);
7330
- const lockPath = path12.join(os.tmpdir(), `codebase-snapshot-${key}.lock`);
7576
+ const lockPath = path13.join(os.tmpdir(), `codebase-snapshot-${key}.lock`);
7331
7577
  const payload = `${JSON.stringify({
7332
7578
  pid: process.pid,
7333
7579
  stagingRoot,
@@ -7336,22 +7582,22 @@ function acquireRunLock(stagingRoot) {
7336
7582
  `;
7337
7583
  for (let attempt = 0; attempt < 2; attempt += 1) {
7338
7584
  try {
7339
- const handle = fs11.openSync(lockPath, "wx");
7585
+ const handle = fs12.openSync(lockPath, "wx");
7340
7586
  try {
7341
- fs11.writeSync(handle, payload);
7587
+ fs12.writeSync(handle, payload);
7342
7588
  } finally {
7343
- fs11.closeSync(handle);
7589
+ fs12.closeSync(handle);
7344
7590
  }
7345
7591
  return () => {
7346
7592
  try {
7347
- fs11.rmSync(lockPath, { force: true });
7593
+ fs12.rmSync(lockPath, { force: true });
7348
7594
  } catch {
7349
7595
  }
7350
7596
  };
7351
7597
  } catch (err) {
7352
7598
  if (err.code !== "EEXIST") throw err;
7353
7599
  if (attempt === 0 && lockOwnerIsGone(lockPath)) {
7354
- fs11.rmSync(lockPath, { force: true });
7600
+ fs12.rmSync(lockPath, { force: true });
7355
7601
  continue;
7356
7602
  }
7357
7603
  throw new Error(
@@ -7364,7 +7610,7 @@ function acquireRunLock(stagingRoot) {
7364
7610
  function lockKeyFor(stagingRoot) {
7365
7611
  let key = stagingRoot;
7366
7612
  try {
7367
- key = fs11.realpathSync(stagingRoot);
7613
+ key = fs12.realpathSync(stagingRoot);
7368
7614
  } catch {
7369
7615
  }
7370
7616
  if (process.platform === "win32" || process.platform === "darwin") key = key.toLowerCase();
@@ -7373,7 +7619,7 @@ function lockKeyFor(stagingRoot) {
7373
7619
  function lockOwnerIsGone(lockPath) {
7374
7620
  let raw;
7375
7621
  try {
7376
- raw = fs11.readFileSync(lockPath, "utf8");
7622
+ raw = fs12.readFileSync(lockPath, "utf8");
7377
7623
  } catch {
7378
7624
  return false;
7379
7625
  }
@@ -7393,12 +7639,12 @@ function lockOwnerIsGone(lockPath) {
7393
7639
  }
7394
7640
  function writeManifestAtomically(manifestPath, manifest) {
7395
7641
  const tempPath = `${manifestPath}.${process.pid}.tmp`;
7396
- fs11.writeFileSync(tempPath, JSON.stringify(manifest, null, 2), "utf8");
7642
+ fs12.writeFileSync(tempPath, JSON.stringify(manifest, null, 2), "utf8");
7397
7643
  try {
7398
- fs11.renameSync(tempPath, manifestPath);
7644
+ fs12.renameSync(tempPath, manifestPath);
7399
7645
  } catch (err) {
7400
7646
  try {
7401
- fs11.rmSync(tempPath, { force: true });
7647
+ fs12.rmSync(tempPath, { force: true });
7402
7648
  } catch {
7403
7649
  }
7404
7650
  throw err;
@@ -7421,31 +7667,31 @@ function swapIntoPlace(stagingDir, outDir) {
7421
7667
  }
7422
7668
  function swapOnce(stagingDir, outDir) {
7423
7669
  const backupDir = `${outDir}.backup-${process.pid}-${Date.now()}`;
7424
- const hadPrevious = fs11.existsSync(outDir);
7425
- if (hadPrevious) fs11.renameSync(outDir, backupDir);
7670
+ const hadPrevious = fs12.existsSync(outDir);
7671
+ if (hadPrevious) fs12.renameSync(outDir, backupDir);
7426
7672
  try {
7427
7673
  try {
7428
- fs11.renameSync(stagingDir, outDir);
7674
+ fs12.renameSync(stagingDir, outDir);
7429
7675
  } catch (err) {
7430
7676
  if (err.code !== "EXDEV") throw err;
7431
7677
  const partialDir = `${outDir}.partial-${process.pid}-${Date.now()}`;
7432
7678
  try {
7433
- fs11.cpSync(stagingDir, partialDir, { recursive: true });
7434
- fs11.renameSync(partialDir, outDir);
7435
- fs11.rmSync(stagingDir, { recursive: true, force: true });
7679
+ fs12.cpSync(stagingDir, partialDir, { recursive: true });
7680
+ fs12.renameSync(partialDir, outDir);
7681
+ fs12.rmSync(stagingDir, { recursive: true, force: true });
7436
7682
  } catch (copyErr) {
7437
7683
  try {
7438
- fs11.rmSync(partialDir, { recursive: true, force: true });
7684
+ fs12.rmSync(partialDir, { recursive: true, force: true });
7439
7685
  } catch {
7440
7686
  }
7441
7687
  throw copyErr;
7442
7688
  }
7443
7689
  }
7444
- if (hadPrevious) fs11.rmSync(backupDir, { recursive: true, force: true });
7690
+ if (hadPrevious) fs12.rmSync(backupDir, { recursive: true, force: true });
7445
7691
  } catch (err) {
7446
- if (hadPrevious && fs11.existsSync(backupDir)) {
7447
- if (fs11.existsSync(outDir)) fs11.rmSync(outDir, { recursive: true, force: true });
7448
- fs11.renameSync(backupDir, outDir);
7692
+ if (hadPrevious && fs12.existsSync(backupDir)) {
7693
+ if (fs12.existsSync(outDir)) fs12.rmSync(outDir, { recursive: true, force: true });
7694
+ fs12.renameSync(backupDir, outDir);
7449
7695
  }
7450
7696
  throw err;
7451
7697
  }
@@ -7540,7 +7786,7 @@ function generateSnapshot(configInput, options) {
7540
7786
  // first run cannot have marked them yet, so the name alone keeps a run from recording its own
7541
7787
  // output — but only at these exact paths, not at every directory that shares the name.
7542
7788
  toolOwnedPaths: [config.outDir, config.tmpDir].map(
7543
- (directory) => path12.relative(config.cwd, path12.resolve(config.cwd, directory)).replace(/\\/g, "/")
7789
+ (directory) => path13.relative(config.cwd, path13.resolve(config.cwd, directory)).replace(/\\/g, "/")
7544
7790
  ).filter((relative7) => relative7.length > 0 && !relative7.startsWith(".."))
7545
7791
  });
7546
7792
  const files = [];
@@ -7561,12 +7807,12 @@ function generateSnapshot(configInput, options) {
7561
7807
  let totalSizeBytes = 0;
7562
7808
  let largeFileCount = 0;
7563
7809
  for (const relativePath of collection.files) {
7564
- const absolutePath = path12.join(config.cwd, relativePath);
7810
+ const absolutePath = path13.join(config.cwd, relativePath);
7565
7811
  let stats;
7566
7812
  try {
7567
- stats = fs11.statSync(absolutePath);
7813
+ stats = fs12.statSync(absolutePath);
7568
7814
  if (!stats.isFile()) {
7569
- const nestedRepository = stats.isDirectory() && fs11.existsSync(path12.join(absolutePath, ".git"));
7815
+ const nestedRepository = stats.isDirectory() && fs12.existsSync(path13.join(absolutePath, ".git"));
7570
7816
  skipped.push(
7571
7817
  nestedRepository ? {
7572
7818
  path: relativePath,
@@ -7586,7 +7832,7 @@ function generateSnapshot(configInput, options) {
7586
7832
  }
7587
7833
  let buffer;
7588
7834
  try {
7589
- buffer = fs11.readFileSync(absolutePath);
7835
+ buffer = fs12.readFileSync(absolutePath);
7590
7836
  } catch {
7591
7837
  skipped.push({ path: relativePath, reason: "read-error" });
7592
7838
  continue;
@@ -7916,12 +8162,12 @@ function generateSnapshot(configInput, options) {
7916
8162
  let stagingDir = null;
7917
8163
  try {
7918
8164
  ensureParentDirectory(outDir, "outDir");
7919
- fs11.mkdirSync(tmpDir, { recursive: true });
8165
+ fs12.mkdirSync(tmpDir, { recursive: true });
7920
8166
  cleanStaleRunDirs(tmpDir);
7921
8167
  const snapshotId = crypto.randomUUID();
7922
8168
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
7923
- stagingDir = path12.join(tmpDir, `${RUN_DIR_PREFIX}${process.pid}-${snapshotId.slice(0, 8)}`);
7924
- fs11.mkdirSync(stagingDir);
8169
+ stagingDir = path13.join(tmpDir, `${RUN_DIR_PREFIX}${process.pid}-${snapshotId.slice(0, 8)}`);
8170
+ fs12.mkdirSync(stagingDir);
7925
8171
  writeOwnershipMarker(stagingDir, {
7926
8172
  generator: GENERATOR_NAME,
7927
8173
  version: GENERATOR_VERSION,
@@ -7931,41 +8177,41 @@ function generateSnapshot(configInput, options) {
7931
8177
  id: snapshotId,
7932
8178
  pid: process.pid
7933
8179
  });
7934
- const partsDir = path12.join(stagingDir, "parts");
7935
- const reportsDir = path12.join(stagingDir, "reports");
7936
- if (artifacts.parts) fs11.mkdirSync(partsDir, { recursive: true });
8180
+ const partsDir = path13.join(stagingDir, "parts");
8181
+ const reportsDir = path13.join(stagingDir, "reports");
8182
+ if (artifacts.parts) fs12.mkdirSync(partsDir, { recursive: true });
7937
8183
  if (artifacts.navigation || artifacts.projectTree || artifacts.audit) {
7938
- fs11.mkdirSync(reportsDir, { recursive: true });
8184
+ fs12.mkdirSync(reportsDir, { recursive: true });
7939
8185
  }
7940
8186
  if (artifacts.parts) {
7941
8187
  for (const part of parts) {
7942
- fs11.writeFileSync(path12.join(partsDir, part.filename), part.markdown, "utf8");
8188
+ fs12.writeFileSync(path13.join(partsDir, part.filename), part.markdown, "utf8");
7943
8189
  }
7944
8190
  }
7945
8191
  if (projectTree !== null) {
7946
- fs11.writeFileSync(path12.join(reportsDir, "project-tree.md"), projectTree, "utf8");
8192
+ fs12.writeFileSync(path13.join(reportsDir, "project-tree.md"), projectTree, "utf8");
7947
8193
  }
7948
8194
  if (artifacts.navigation) {
7949
- fs11.writeFileSync(path12.join(reportsDir, "navigation.md"), generateNavigation(manifest), "utf8");
8195
+ fs12.writeFileSync(path13.join(reportsDir, "navigation.md"), generateNavigation(manifest), "utf8");
7950
8196
  }
7951
8197
  if (artifacts.audit) {
7952
- fs11.writeFileSync(
7953
- path12.join(reportsDir, "audit.md"),
8198
+ fs12.writeFileSync(
8199
+ path13.join(reportsDir, "audit.md"),
7954
8200
  generateAuditReport(manifest, secretFindings, config.secretRules),
7955
8201
  "utf8"
7956
8202
  );
7957
8203
  }
7958
8204
  if (artifacts.readme) {
7959
- fs11.writeFileSync(path12.join(stagingDir, "README.md"), generateReadme(manifest, artifacts), "utf8");
8205
+ fs12.writeFileSync(path13.join(stagingDir, "README.md"), generateReadme(manifest, artifacts), "utf8");
7960
8206
  }
7961
8207
  if (artifacts.manifest) {
7962
- fs11.writeFileSync(path12.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
8208
+ fs12.writeFileSync(path13.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
7963
8209
  }
7964
8210
  if (monolithJson !== null) {
7965
- fs11.writeFileSync(path12.join(stagingDir, "full-codebase.json"), monolithJson, "utf8");
8211
+ fs12.writeFileSync(path13.join(stagingDir, "full-codebase.json"), monolithJson, "utf8");
7966
8212
  }
7967
8213
  if (monolithMarkdown !== null) {
7968
- fs11.writeFileSync(path12.join(stagingDir, "full-codebase.md"), monolithMarkdown, "utf8");
8214
+ fs12.writeFileSync(path13.join(stagingDir, "full-codebase.md"), monolithMarkdown, "utf8");
7969
8215
  }
7970
8216
  writeOwnershipMarker(stagingDir, markerPayload(stagingDir, "complete", snapshotId, createdAt));
7971
8217
  swapIntoPlace(stagingDir, outDir);
@@ -7974,7 +8220,7 @@ function generateSnapshot(configInput, options) {
7974
8220
  const pendingHook = runAfterGenerate(config, manifest);
7975
8221
  const shipHookState = () => {
7976
8222
  if (artifacts.manifest && manifest.warnings.length !== warningsBeforeHook) {
7977
- writeManifestAtomically(path12.join(outDir, "manifest.json"), manifest);
8223
+ writeManifestAtomically(path13.join(outDir, "manifest.json"), manifest);
7978
8224
  }
7979
8225
  writeOwnershipMarker(outDir, markerPayload(outDir, "complete", snapshotId, createdAt));
7980
8226
  };
@@ -7997,7 +8243,7 @@ function generateSnapshot(configInput, options) {
7997
8243
  } catch (err) {
7998
8244
  if (stagingDir !== null) {
7999
8245
  try {
8000
- fs11.rmSync(stagingDir, { recursive: true, force: true });
8246
+ fs12.rmSync(stagingDir, { recursive: true, force: true });
8001
8247
  } catch {
8002
8248
  }
8003
8249
  }
@@ -8011,6 +8257,6 @@ async function generateSnapshotAsync(configInput, options) {
8011
8257
  return generateSnapshot(configInput, options);
8012
8258
  }
8013
8259
 
8014
- export { ARTIFACT_NAMES, DEFAULT_ANSWERS, DEFAULT_SECRET_PATTERNS, GENERATOR_NAME, GENERATOR_VERSION, LANGUAGE_PROFILES, MIN_MAX_PART_BYTES, PRESETS, PromptCancelled, SCHEMA_VERSION, anchorForPath, appendGitignoreEntries, assertReplaceable, assertUsableConfigInput, collectFiles, compareManifests, countInvalidUtf8Bytes, countLines, decodeText, defaultIO, defineConfig, describeManifestShapeProblem, detectLanguage, detectPreset, escapeControls, explainPath, fenceForContent, fenceForText, findConfigFile, firstRunMessage, formatNumber, generateProjectTree, generateSnapshot, generateSnapshotAsync, getPreset, gitignorePath, globToRegExp, hasPriorSnapshot, isBinaryBuffer, isBinaryExtension, isBinaryFile, isDiscoveryMode, isEffectivelyEmpty, isInteractive, isResolvedConfig, isSensitivePath, listPresetNames, loadConfigFile, loadConfigFileDetailed, loadManifest, markResolvedConfig, matchRule, matchesExclude, normalizeResolvedConfig, parseByteSize, partitionFiles, planFirstRun, profileForPath, renderConfig, renderDiffText, renderExplainText, renumberParts, resolveConfig, resolveSafeOutputDirs, runInit, scanAndRedactSecrets, stripJsonComments, summarizeJson, summarizeMarkdown, summarizeTypeScriptSource, summarizeWithProfile, supportsTypeScriptImports, truncatePreview, truncateToBytes, unknownPresetMessage, validateSnapshot };
8015
- //# sourceMappingURL=chunk-FCWD4LY7.js.map
8016
- //# sourceMappingURL=chunk-FCWD4LY7.js.map
8260
+ export { ARTIFACT_NAMES, CHECK_INTERVAL_MS, DEFAULT_ANSWERS, DEFAULT_SECRET_PATTERNS, FAILURE_INTERVAL_MS, GENERATOR_NAME, GENERATOR_VERSION, LANGUAGE_PROFILES, MIN_MAX_PART_BYTES, PACKAGE_LATEST_URL, PRESETS, PromptCancelled, REQUEST_TIMEOUT_MS, SCHEMA_VERSION, anchorForPath, appendGitignoreEntries, assertReplaceable, assertUsableConfigInput, cacheDirectory, cacheFilePath, checkForUpdate, collectFiles, compareManifests, countInvalidUtf8Bytes, countLines, decodeText, defaultIO, defineConfig, describeManifestShapeProblem, detectLanguage, detectPreset, escapeControls, explainPath, fenceForContent, fenceForText, fetchLatestVersion, findConfigFile, firstRunMessage, formatNumber, formatUpdateNotice, generateProjectTree, generateSnapshot, generateSnapshotAsync, getPreset, gitignorePath, globToRegExp, hasPriorSnapshot, isBinaryBuffer, isBinaryExtension, isBinaryFile, isDiscoveryMode, isEffectivelyEmpty, isInteractive, isNewer, isResolvedConfig, isSensitivePath, listPresetNames, loadConfigFile, loadConfigFileDetailed, loadManifest, markResolvedConfig, matchRule, matchesExclude, normalizeResolvedConfig, parseByteSize, partitionFiles, planFirstRun, profileForPath, renderConfig, renderDiffText, renderExplainText, renumberParts, resolveConfig, resolveSafeOutputDirs, runInit, scanAndRedactSecrets, shouldCheck, stripJsonComments, summarizeJson, summarizeMarkdown, summarizeTypeScriptSource, summarizeWithProfile, supportsTypeScriptImports, truncatePreview, truncateToBytes, unknownPresetMessage, validateSnapshot };
8261
+ //# sourceMappingURL=chunk-3KUL3QRH.js.map
8262
+ //# sourceMappingURL=chunk-3KUL3QRH.js.map