codebase-snapshot 0.9.5 → 0.9.7

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.
package/dist/bin.js CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { spawnSync } from "child_process";
5
- import * as fs16 from "fs";
6
- import * as path17 from "path";
5
+ import * as fs17 from "fs";
6
+ import * as path18 from "path";
7
7
  import { parseArgs } from "util";
8
8
 
9
9
  // src/diff.ts
@@ -4346,7 +4346,7 @@ function gitignorePath(cwd, filePath) {
4346
4346
 
4347
4347
  // src/version.ts
4348
4348
  var GENERATOR_NAME = "codebase-snapshot";
4349
- var GENERATOR_VERSION = "0.9.5";
4349
+ var GENERATOR_VERSION = "0.9.7";
4350
4350
  var LEGACY_GENERATOR_NAMES = ["@ankurhalder/codebase-snapshot"];
4351
4351
  function isOurGeneratorName(name) {
4352
4352
  if (typeof name !== "string") return false;
@@ -4509,6 +4509,57 @@ function toggleIndex(selected, index) {
4509
4509
  else next.add(index);
4510
4510
  return next;
4511
4511
  }
4512
+ function isWideCodePoint(code) {
4513
+ return code >= 4352 && code <= 4447 || // Hangul Jamo
4514
+ code >= 11904 && code <= 12350 || // CJK radicals, Kangxi, CJK symbols
4515
+ code >= 12353 && code <= 13311 || // kana through CJK compatibility
4516
+ code >= 13312 && code <= 19903 || // CJK extension A
4517
+ code >= 19968 && code <= 40959 || // CJK unified ideographs
4518
+ code >= 40960 && code <= 42191 || // Yi
4519
+ code >= 44032 && code <= 55203 || // Hangul syllables
4520
+ code >= 63744 && code <= 64255 || // CJK compatibility ideographs
4521
+ code >= 65072 && code <= 65135 || // CJK compatibility forms
4522
+ code >= 65280 && code <= 65376 || // fullwidth forms
4523
+ code >= 65504 && code <= 65510 || code >= 127744 && code <= 129535 || // emoji and pictographs
4524
+ code >= 131072 && code <= 262141;
4525
+ }
4526
+ var ANSI_PATTERN = /\u001b\[[0-9;?]*[A-Za-z]/g;
4527
+ function displayWidth(line) {
4528
+ let width = 0;
4529
+ for (const character of line.replace(ANSI_PATTERN, "")) {
4530
+ width += isWideCodePoint(character.codePointAt(0) ?? 0) ? 2 : 1;
4531
+ }
4532
+ return width;
4533
+ }
4534
+ function wrapOneLine(line, limit) {
4535
+ if (displayWidth(line) <= limit) return [line];
4536
+ const indent = /^[ \t]*/.exec(line)?.[0] ?? "";
4537
+ const continuation = `${indent} `;
4538
+ const rows = [];
4539
+ let prefix = indent;
4540
+ let rest = line.slice(indent.length).trimEnd();
4541
+ while (rest.length > 0) {
4542
+ const room = limit - displayWidth(prefix);
4543
+ if (room <= 0 || displayWidth(rest) <= room) {
4544
+ rows.push(prefix + rest);
4545
+ break;
4546
+ }
4547
+ let cut = room;
4548
+ const space = rest.slice(0, room).lastIndexOf(" ");
4549
+ if (space > 0) cut = space;
4550
+ const taken = rest.slice(0, cut).trimEnd();
4551
+ rows.push(`${prefix}${taken.length > 0 ? taken : rest.slice(0, cut)}`);
4552
+ rest = rest.slice(cut).trimStart();
4553
+ prefix = continuation;
4554
+ }
4555
+ return rows;
4556
+ }
4557
+ function wrapLines(text2, limit) {
4558
+ const width = Math.max(8, Math.floor(limit));
4559
+ const rows = [];
4560
+ for (const line of text2.split("\n")) rows.push(...wrapOneLine(line, width));
4561
+ return rows;
4562
+ }
4512
4563
  function marker(active) {
4513
4564
  return active ? "\u276F" : " ";
4514
4565
  }
@@ -4586,14 +4637,27 @@ var Frame = class {
4586
4637
  drawn = 0;
4587
4638
  draw(text2) {
4588
4639
  this.erase();
4589
- this.output.write(`${text2}
4640
+ const rows = wrapLines(text2, this.width());
4641
+ this.output.write(`${rows.join("\n")}
4590
4642
  `);
4591
- this.drawn = text2.split("\n").length;
4643
+ this.drawn = rows.length;
4592
4644
  }
4593
4645
  erase() {
4594
4646
  if (this.drawn > 0) this.output.write(`\x1B[${this.drawn}A\x1B[0J`);
4595
4647
  this.drawn = 0;
4596
4648
  }
4649
+ /**
4650
+ * The usable width, in cells.
4651
+ *
4652
+ * Two cells of slack: an ambiguous-width glyph (`◆`, `❯`, `←`) renders two cells in some fonts
4653
+ * and one in others, and a row that lands exactly on the last column is the one case a terminal
4654
+ * may or may not wrap. Below that, a line cannot reach the edge to begin with.
4655
+ */
4656
+ width() {
4657
+ const columns = this.output.columns;
4658
+ if (typeof columns !== "number" || !Number.isFinite(columns) || columns <= 0) return 80;
4659
+ return Math.max(8, Math.floor(columns) - 2);
4660
+ }
4597
4661
  };
4598
4662
  function isCancel(key) {
4599
4663
  return key.ctrl === true && key.name === "c" || key.ctrl === true && key.name === "d";
@@ -5289,9 +5353,9 @@ function hasPriorSnapshot(cwd, outDir) {
5289
5353
  // src/index.ts
5290
5354
  import * as crypto3 from "crypto";
5291
5355
  import { AsyncLocalStorage } from "async_hooks";
5292
- import * as fs11 from "fs";
5293
- import * as os from "os";
5294
- import * as path12 from "path";
5356
+ import * as fs12 from "fs";
5357
+ import * as os2 from "os";
5358
+ import * as path13 from "path";
5295
5359
 
5296
5360
  // src/ast/profiles/shared.ts
5297
5361
  var MAX_SUMMARY_CHARS = 1e6;
@@ -5515,9 +5579,9 @@ var JAVA_METHOD = /^\s+(?:public|private|protected)\s+(?:static\s+)?(?:final\s+)
5515
5579
  var jvmProfile = {
5516
5580
  id: "jvm",
5517
5581
  extensions: [".java", ".kt", ".kts", ".scala"],
5518
- summarize(path18, content) {
5582
+ summarize(path19, content) {
5519
5583
  const summary = emptySummary();
5520
- const lower = path18.toLowerCase();
5584
+ const lower = path19.toLowerCase();
5521
5585
  const isJava = lower.endsWith(".java");
5522
5586
  const isKotlin = lower.endsWith(".kt") || lower.endsWith(".kts");
5523
5587
  eachLine(content, (line) => {
@@ -5973,16 +6037,16 @@ function summarizeTypeScriptSource(relativePath, content) {
5973
6037
  // src/ast/profiles/sfc.ts
5974
6038
  var SCRIPT_BLOCK = /<script[^>]*>([\s\S]*?)<\/script>/gi;
5975
6039
  var ASTRO_FRONTMATTER = /^\uFEFF?---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*(?=\r?\n|$)/;
5976
- function componentName(path18) {
5977
- const base = path18.split("/").pop() ?? path18;
6040
+ function componentName(path19) {
6041
+ const base = path19.split("/").pop() ?? path19;
5978
6042
  return base.replace(/\.[^.]+$/, "");
5979
6043
  }
5980
6044
  var sfcProfile = {
5981
6045
  id: "sfc",
5982
6046
  extensions: [".vue", ".svelte", ".astro"],
5983
- summarize(path18, content) {
6047
+ summarize(path19, content) {
5984
6048
  let script = "";
5985
- if (path18.toLowerCase().endsWith(".astro")) {
6049
+ if (path19.toLowerCase().endsWith(".astro")) {
5986
6050
  const frontmatter = ASTRO_FRONTMATTER.exec(content);
5987
6051
  if (frontmatter) script += `${frontmatter[1]}
5988
6052
  `;
@@ -5991,7 +6055,7 @@ var sfcProfile = {
5991
6055
  script += `${match[1]}
5992
6056
  `;
5993
6057
  }
5994
- const name = componentName(path18);
6058
+ const name = componentName(path19);
5995
6059
  if (!script.trim()) {
5996
6060
  const summary2 = emptySummary();
5997
6061
  if (name) {
@@ -6025,15 +6089,15 @@ for (const profile of LANGUAGE_PROFILES) {
6025
6089
  BY_EXTENSION.set(extension.toLowerCase(), profile);
6026
6090
  }
6027
6091
  }
6028
- function profileForPath(path18) {
6029
- const lower = path18.toLowerCase();
6092
+ function profileForPath(path19) {
6093
+ const lower = path19.toLowerCase();
6030
6094
  const dot = lower.lastIndexOf(".");
6031
6095
  if (dot === -1) return null;
6032
6096
  return BY_EXTENSION.get(lower.slice(dot)) ?? null;
6033
6097
  }
6034
- function summarizeWithProfile(path18, content) {
6035
- const profile = profileForPath(path18);
6036
- return profile ? profile.summarize(path18, content) : null;
6098
+ function summarizeWithProfile(path19, content) {
6099
+ const profile = profileForPath(path19);
6100
+ return profile ? profile.summarize(path19, content) : null;
6037
6101
  }
6038
6102
 
6039
6103
  // src/ast/structured.ts
@@ -6882,6 +6946,168 @@ function generateProjectTree(filePaths) {
6882
6946
  return ["# Project Tree", "", `${fence}text`, ...lines, fence, ""].join("\n");
6883
6947
  }
6884
6948
 
6949
+ // src/update-check.ts
6950
+ import * as fs11 from "fs";
6951
+ import * as https from "https";
6952
+ import * as os from "os";
6953
+ import * as path12 from "path";
6954
+ var PACKAGE_LATEST_URL = "https://registry.npmjs.org/codebase-snapshot/latest";
6955
+ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
6956
+ var FAILURE_INTERVAL_MS = 60 * 60 * 1e3;
6957
+ var REQUEST_TIMEOUT_MS = 1200;
6958
+ function versionParts(value) {
6959
+ const core = value.trim().replace(/^v/i, "").split("-")[0];
6960
+ return core.split(".").map((part) => {
6961
+ const parsed = Number(part);
6962
+ return Number.isFinite(parsed) ? parsed : 0;
6963
+ });
6964
+ }
6965
+ function isNewer(candidate, current) {
6966
+ const left = versionParts(candidate);
6967
+ const right = versionParts(current);
6968
+ const length = Math.max(left.length, right.length);
6969
+ for (let index = 0; index < length; index += 1) {
6970
+ const a = left[index] ?? 0;
6971
+ const b = right[index] ?? 0;
6972
+ if (a !== b) return a > b;
6973
+ }
6974
+ return false;
6975
+ }
6976
+ function cacheDirectory(env = process.env, platform = process.platform) {
6977
+ if (platform === "win32") {
6978
+ const base2 = env.LOCALAPPDATA ?? path12.join(os.homedir(), "AppData", "Local");
6979
+ return path12.join(base2, "codebase-snapshot");
6980
+ }
6981
+ if (platform === "darwin") {
6982
+ return path12.join(os.homedir(), "Library", "Caches", "codebase-snapshot");
6983
+ }
6984
+ const base = env.XDG_CACHE_HOME ?? path12.join(os.homedir(), ".cache");
6985
+ return path12.join(base, "codebase-snapshot");
6986
+ }
6987
+ function cacheFilePath(env = process.env) {
6988
+ return path12.join(cacheDirectory(env), "update-check.json");
6989
+ }
6990
+ function shouldCheck(argv, env) {
6991
+ const disabled = ["1", "true", "yes"].includes(
6992
+ String(env.CODEBASE_SNAPSHOT_NO_UPDATE_CHECK ?? "").toLowerCase()
6993
+ );
6994
+ if (disabled) return false;
6995
+ if (env.CI !== void 0 && env.CI !== "" && env.CI !== "false" && env.CI !== "0") return false;
6996
+ const args = argv.map((argument) => argument.toLowerCase());
6997
+ if (args.includes("--no-update-check")) return false;
6998
+ for (const skip of ["mcp", "describe", "skill", "--version", "-v", "--help", "-h"]) {
6999
+ if (args.includes(skip)) return false;
7000
+ }
7001
+ if (args.some((argument) => argument.includes("json"))) return false;
7002
+ return true;
7003
+ }
7004
+ function readCache(file) {
7005
+ let raw;
7006
+ try {
7007
+ raw = fs11.readFileSync(file, "utf8");
7008
+ } catch {
7009
+ return null;
7010
+ }
7011
+ try {
7012
+ const parsed = JSON.parse(raw);
7013
+ if (typeof parsed !== "object" || parsed === null) return null;
7014
+ const candidate = parsed;
7015
+ if (typeof candidate.checkedAt !== "number") return null;
7016
+ const latest = typeof candidate.latest === "string" ? candidate.latest : null;
7017
+ return { checkedAt: candidate.checkedAt, latest };
7018
+ } catch {
7019
+ return null;
7020
+ }
7021
+ }
7022
+ function writeCache(file, entry) {
7023
+ try {
7024
+ fs11.mkdirSync(path12.dirname(file), { recursive: true });
7025
+ fs11.writeFileSync(file, `${JSON.stringify(entry)}
7026
+ `, "utf8");
7027
+ } catch {
7028
+ }
7029
+ }
7030
+ function fetchLatestVersion(url = PACKAGE_LATEST_URL, timeoutMs = REQUEST_TIMEOUT_MS) {
7031
+ return new Promise((resolve9) => {
7032
+ let settled = false;
7033
+ const finish = (value) => {
7034
+ if (settled) return;
7035
+ settled = true;
7036
+ resolve9(value);
7037
+ };
7038
+ const request = https.get(
7039
+ url,
7040
+ {
7041
+ headers: {
7042
+ accept: "application/json",
7043
+ "user-agent": "codebase-snapshot (update check)"
7044
+ }
7045
+ },
7046
+ (response) => {
7047
+ if (response.statusCode !== 200) {
7048
+ response.resume();
7049
+ finish(null);
7050
+ return;
7051
+ }
7052
+ let body = "";
7053
+ response.setEncoding("utf8");
7054
+ response.on("data", (chunk) => {
7055
+ body += chunk;
7056
+ if (body.length > 64 * 1024) {
7057
+ request.destroy();
7058
+ finish(null);
7059
+ }
7060
+ });
7061
+ response.on("end", () => {
7062
+ try {
7063
+ const parsed = JSON.parse(body);
7064
+ finish(typeof parsed.version === "string" ? parsed.version : null);
7065
+ } catch {
7066
+ finish(null);
7067
+ }
7068
+ });
7069
+ }
7070
+ );
7071
+ request.on("error", () => finish(null));
7072
+ request.setTimeout(timeoutMs, () => {
7073
+ request.destroy();
7074
+ finish(null);
7075
+ });
7076
+ });
7077
+ }
7078
+ async function checkForUpdate(options) {
7079
+ if (options.enabled === false) return null;
7080
+ const now = options.now ?? (() => Date.now());
7081
+ const fetchLatest = options.fetchLatest ?? fetchLatestVersion;
7082
+ let latest = null;
7083
+ try {
7084
+ const cached = readCache(options.cacheFile);
7085
+ let needsFetch = cached === null;
7086
+ if (cached) {
7087
+ const age = now() - cached.checkedAt;
7088
+ if (cached.latest === null) {
7089
+ needsFetch = age >= FAILURE_INTERVAL_MS;
7090
+ } else {
7091
+ latest = cached.latest;
7092
+ needsFetch = age >= CHECK_INTERVAL_MS;
7093
+ }
7094
+ }
7095
+ if (needsFetch) {
7096
+ const fetched = await fetchLatest(PACKAGE_LATEST_URL, REQUEST_TIMEOUT_MS);
7097
+ writeCache(options.cacheFile, { checkedAt: now(), latest: fetched });
7098
+ latest = fetched;
7099
+ }
7100
+ } catch {
7101
+ return null;
7102
+ }
7103
+ if (!latest) return null;
7104
+ return isNewer(latest, options.current) ? { current: options.current, latest } : null;
7105
+ }
7106
+ function formatUpdateNotice(notice) {
7107
+ return `\u2191 codebase-snapshot ${notice.latest} is available \u2014 you have ${notice.current}.
7108
+ npm install -g codebase-snapshot`;
7109
+ }
7110
+
6885
7111
  // src/index.ts
6886
7112
  var SCHEMA_VERSION = "3.0.0";
6887
7113
  var SUMMARY_MAX_SOURCE_BYTES = 2 * 1024 * 1024;
@@ -6963,13 +7189,13 @@ function buildImportResolver(files) {
6963
7189
  const relativePath = file.relativePath;
6964
7190
  remember(byPath, relativePath, relativePath);
6965
7191
  remember(byPathFolded, relativePath.toLowerCase(), relativePath);
6966
- const extension = path12.posix.extname(relativePath);
7192
+ const extension = path13.posix.extname(relativePath);
6967
7193
  if (!SOURCE_EXTENSIONS.has(extension)) continue;
6968
7194
  const stem = relativePath.slice(0, -extension.length);
6969
7195
  remember(byStem, stem, relativePath);
6970
7196
  remember(byStemFolded, stem.toLowerCase(), relativePath);
6971
- if (path12.posix.basename(stem) === "index") {
6972
- const directory = path12.posix.dirname(stem);
7197
+ if (path13.posix.basename(stem) === "index") {
7198
+ const directory = path13.posix.dirname(stem);
6973
7199
  remember(byStem, directory, relativePath);
6974
7200
  remember(byStemFolded, directory.toLowerCase(), relativePath);
6975
7201
  }
@@ -6978,8 +7204,8 @@ function buildImportResolver(files) {
6978
7204
  }
6979
7205
  function resolveSpecifier(fromFile, specifier, resolver) {
6980
7206
  if (!RELATIVE_SPECIFIER.test(specifier)) return null;
6981
- const joined = path12.posix.normalize(
6982
- path12.posix.join(path12.posix.dirname(fromFile), specifier)
7207
+ const joined = path13.posix.normalize(
7208
+ path13.posix.join(path13.posix.dirname(fromFile), specifier)
6983
7209
  );
6984
7210
  const exact = (key) => resolver.byPath.get(key) ?? resolver.byPathFolded.get(key.toLowerCase()) ?? null;
6985
7211
  const direct = exact(joined);
@@ -7072,11 +7298,11 @@ function verifyInMemory(files, parts, maxPartBytes) {
7072
7298
  return errors;
7073
7299
  }
7074
7300
  function resolveSafeOutputDirs(config) {
7075
- const cwd = path12.resolve(config.cwd);
7076
- const outDir = path12.resolve(cwd, config.outDir);
7077
- const tmpDir = path12.resolve(cwd, config.tmpDir);
7078
- const root = path12.parse(cwd).root;
7079
- const contains = (parent, child) => child === parent || child.startsWith(`${parent}${path12.sep}`);
7301
+ const cwd = path13.resolve(config.cwd);
7302
+ const outDir = path13.resolve(cwd, config.outDir);
7303
+ const tmpDir = path13.resolve(cwd, config.tmpDir);
7304
+ const root = path13.parse(cwd).root;
7305
+ const contains = (parent, child) => child === parent || child.startsWith(`${parent}${path13.sep}`);
7080
7306
  const reject = (reason) => {
7081
7307
  throw new Error(
7082
7308
  `Refusing to generate: ${reason}. outDir=${outDir} tmpDir=${tmpDir} cwd=${cwd}`
@@ -7132,14 +7358,14 @@ function listEntries(dir) {
7132
7358
  const walk = (absolute, prefix) => {
7133
7359
  let children;
7134
7360
  try {
7135
- children = fs11.readdirSync(absolute, { withFileTypes: true });
7361
+ children = fs12.readdirSync(absolute, { withFileTypes: true });
7136
7362
  } catch {
7137
7363
  return;
7138
7364
  }
7139
7365
  for (const child of children) {
7140
7366
  const relative11 = prefix === "" ? child.name : `${prefix}/${child.name}`;
7141
7367
  entries.push(relative11);
7142
- if (child.isDirectory()) walk(path12.join(absolute, child.name), relative11);
7368
+ if (child.isDirectory()) walk(path13.join(absolute, child.name), relative11);
7143
7369
  }
7144
7370
  };
7145
7371
  walk(dir, "");
@@ -7156,28 +7382,28 @@ function markerPayload(dir, state, id, createdAt) {
7156
7382
  pid: process.pid,
7157
7383
  entries: listEntries(dir)
7158
7384
  };
7159
- const manifestPath = path12.join(dir, "manifest.json");
7160
- if (fs11.existsSync(manifestPath)) {
7161
- marker2.manifestSha256 = sha256Hex2(fs11.readFileSync(manifestPath));
7385
+ const manifestPath = path13.join(dir, "manifest.json");
7386
+ if (fs12.existsSync(manifestPath)) {
7387
+ marker2.manifestSha256 = sha256Hex2(fs12.readFileSync(manifestPath));
7162
7388
  }
7163
7389
  return marker2;
7164
7390
  }
7165
7391
  function writeOwnershipMarker(dir, marker2) {
7166
- fs11.writeFileSync(
7167
- path12.join(dir, OWNERSHIP_MARKER),
7392
+ fs12.writeFileSync(
7393
+ path13.join(dir, OWNERSHIP_MARKER),
7168
7394
  `${JSON.stringify(marker2, null, 2)}
7169
7395
  `,
7170
7396
  "utf8"
7171
7397
  );
7172
7398
  }
7173
7399
  function readOwnershipMarker(dir) {
7174
- const markerPath = path12.join(dir, OWNERSHIP_MARKER);
7175
- if (!fs11.existsSync(markerPath)) {
7400
+ const markerPath = path13.join(dir, OWNERSHIP_MARKER);
7401
+ if (!fs12.existsSync(markerPath)) {
7176
7402
  return { marker: null, problem: "it holds no .codebase-snapshot marker" };
7177
7403
  }
7178
7404
  let raw;
7179
7405
  try {
7180
- raw = fs11.readFileSync(markerPath, "utf8");
7406
+ raw = fs12.readFileSync(markerPath, "utf8");
7181
7407
  } catch {
7182
7408
  return { marker: null, problem: "its .codebase-snapshot marker could not be read" };
7183
7409
  }
@@ -7245,11 +7471,11 @@ function assessSnapshotDirectory(dir) {
7245
7471
  marker: marker2
7246
7472
  };
7247
7473
  }
7248
- const manifestPath = path12.join(dir, "manifest.json");
7249
- if (fs11.existsSync(manifestPath)) {
7474
+ const manifestPath = path13.join(dir, "manifest.json");
7475
+ if (fs12.existsSync(manifestPath)) {
7250
7476
  let raw;
7251
7477
  try {
7252
- raw = fs11.readFileSync(manifestPath, "utf8");
7478
+ raw = fs12.readFileSync(manifestPath, "utf8");
7253
7479
  } catch {
7254
7480
  return {
7255
7481
  owned: false,
@@ -7331,13 +7557,13 @@ function containsNoFiles(dir) {
7331
7557
  const current = pending.pop();
7332
7558
  let entries;
7333
7559
  try {
7334
- entries = fs11.readdirSync(current, { withFileTypes: true });
7560
+ entries = fs12.readdirSync(current, { withFileTypes: true });
7335
7561
  } catch {
7336
7562
  return false;
7337
7563
  }
7338
7564
  for (const entry of entries) {
7339
7565
  if (entry.isDirectory()) {
7340
- pending.push(path12.join(current, entry.name));
7566
+ pending.push(path13.join(current, entry.name));
7341
7567
  } else if (!IGNORABLE_ENTRIES.has(entry.name)) {
7342
7568
  return false;
7343
7569
  }
@@ -7346,13 +7572,13 @@ function containsNoFiles(dir) {
7346
7572
  return true;
7347
7573
  }
7348
7574
  function assertReplaceable(target, label, secretRules) {
7349
- if (!fs11.existsSync(target)) return;
7350
- if (!fs11.statSync(target).isDirectory()) {
7575
+ if (!fs12.existsSync(target)) return;
7576
+ if (!fs12.statSync(target).isDirectory()) {
7351
7577
  throw new Error(
7352
7578
  `Refusing to write into ${label} ${target}: it exists but is not a directory.`
7353
7579
  );
7354
7580
  }
7355
- const entries = fs11.readdirSync(target);
7581
+ const entries = fs12.readdirSync(target);
7356
7582
  if (entries.length === 0) return;
7357
7583
  if (entries.every((name) => IGNORABLE_ENTRIES.has(name))) return;
7358
7584
  if (containsNoFiles(target)) return;
@@ -7372,18 +7598,18 @@ function assertReplaceable(target, label, secretRules) {
7372
7598
  );
7373
7599
  }
7374
7600
  function assertStagingRootUsable(tmpDir, secretRules) {
7375
- if (!fs11.existsSync(tmpDir)) return;
7376
- if (!fs11.statSync(tmpDir).isDirectory()) {
7601
+ if (!fs12.existsSync(tmpDir)) return;
7602
+ if (!fs12.statSync(tmpDir).isDirectory()) {
7377
7603
  throw new Error(`Refusing to write into tmpDir ${tmpDir}: it exists but is not a directory.`);
7378
7604
  }
7379
- const entries = fs11.readdirSync(tmpDir);
7605
+ const entries = fs12.readdirSync(tmpDir);
7380
7606
  if (entries.length === 0) return;
7381
7607
  const foreign = entries.filter((name) => {
7382
- const full = path12.join(tmpDir, name);
7608
+ const full = path13.join(tmpDir, name);
7383
7609
  if (!name.startsWith(RUN_DIR_PREFIX)) return true;
7384
7610
  let stats;
7385
7611
  try {
7386
- stats = fs11.statSync(full);
7612
+ stats = fs12.statSync(full);
7387
7613
  } catch {
7388
7614
  return true;
7389
7615
  }
@@ -7391,7 +7617,7 @@ function assertStagingRootUsable(tmpDir, secretRules) {
7391
7617
  const { marker: marker2 } = readOwnershipMarker(full);
7392
7618
  if (marker2) return false;
7393
7619
  try {
7394
- return fs11.readdirSync(full).length > 0;
7620
+ return fs12.readdirSync(full).length > 0;
7395
7621
  } catch {
7396
7622
  return true;
7397
7623
  }
@@ -7406,13 +7632,13 @@ function assertStagingRootUsable(tmpDir, secretRules) {
7406
7632
  function cleanStaleRunDirs(tmpDir) {
7407
7633
  let entries;
7408
7634
  try {
7409
- entries = fs11.readdirSync(tmpDir);
7635
+ entries = fs12.readdirSync(tmpDir);
7410
7636
  } catch {
7411
7637
  return;
7412
7638
  }
7413
7639
  for (const name of entries) {
7414
7640
  if (!name.startsWith(RUN_DIR_PREFIX)) continue;
7415
- const full = path12.join(tmpDir, name);
7641
+ const full = path13.join(tmpDir, name);
7416
7642
  const { marker: marker2 } = readOwnershipMarker(full);
7417
7643
  if (marker2) {
7418
7644
  const created = Date.parse(marker2.createdAt);
@@ -7420,33 +7646,33 @@ function cleanStaleRunDirs(tmpDir) {
7420
7646
  const abandoned = typeof marker2.pid === "number" && !isProcessAlive(marker2.pid);
7421
7647
  if (aged || abandoned) {
7422
7648
  try {
7423
- fs11.rmSync(full, { recursive: true, force: true });
7649
+ fs12.rmSync(full, { recursive: true, force: true });
7424
7650
  } catch {
7425
7651
  }
7426
7652
  }
7427
7653
  continue;
7428
7654
  }
7429
7655
  try {
7430
- if (fs11.readdirSync(full).length === 0) fs11.rmSync(full, { recursive: true, force: true });
7656
+ if (fs12.readdirSync(full).length === 0) fs12.rmSync(full, { recursive: true, force: true });
7431
7657
  } catch {
7432
7658
  }
7433
7659
  }
7434
7660
  }
7435
7661
  function removeIfEmpty(dir) {
7436
7662
  try {
7437
- if (fs11.readdirSync(dir).length === 0) fs11.rmSync(dir, { recursive: true, force: true });
7663
+ if (fs12.readdirSync(dir).length === 0) fs12.rmSync(dir, { recursive: true, force: true });
7438
7664
  } catch {
7439
7665
  }
7440
7666
  }
7441
7667
  function ensureParentDirectory(target, label) {
7442
- const parent = path12.dirname(target);
7443
- if (fs11.existsSync(parent) && !fs11.statSync(parent).isDirectory()) {
7668
+ const parent = path13.dirname(target);
7669
+ if (fs12.existsSync(parent) && !fs12.statSync(parent).isDirectory()) {
7444
7670
  throw new Error(
7445
7671
  `Refusing to create ${label} ${target}: ${parent} exists but is not a directory.`
7446
7672
  );
7447
7673
  }
7448
7674
  try {
7449
- fs11.mkdirSync(parent, { recursive: true });
7675
+ fs12.mkdirSync(parent, { recursive: true });
7450
7676
  } catch (err) {
7451
7677
  throw new Error(
7452
7678
  `Refusing to create ${label} ${target}: its parent ${parent} could not be created (${err.message}).`
@@ -7455,7 +7681,7 @@ function ensureParentDirectory(target, label) {
7455
7681
  }
7456
7682
  function acquireRunLock(stagingRoot) {
7457
7683
  const key = lockKeyFor(stagingRoot);
7458
- const lockPath = path12.join(os.tmpdir(), `codebase-snapshot-${key}.lock`);
7684
+ const lockPath = path13.join(os2.tmpdir(), `codebase-snapshot-${key}.lock`);
7459
7685
  const payload = `${JSON.stringify({
7460
7686
  pid: process.pid,
7461
7687
  stagingRoot,
@@ -7464,22 +7690,22 @@ function acquireRunLock(stagingRoot) {
7464
7690
  `;
7465
7691
  for (let attempt = 0; attempt < 2; attempt += 1) {
7466
7692
  try {
7467
- const handle = fs11.openSync(lockPath, "wx");
7693
+ const handle = fs12.openSync(lockPath, "wx");
7468
7694
  try {
7469
- fs11.writeSync(handle, payload);
7695
+ fs12.writeSync(handle, payload);
7470
7696
  } finally {
7471
- fs11.closeSync(handle);
7697
+ fs12.closeSync(handle);
7472
7698
  }
7473
7699
  return () => {
7474
7700
  try {
7475
- fs11.rmSync(lockPath, { force: true });
7701
+ fs12.rmSync(lockPath, { force: true });
7476
7702
  } catch {
7477
7703
  }
7478
7704
  };
7479
7705
  } catch (err) {
7480
7706
  if (err.code !== "EEXIST") throw err;
7481
7707
  if (attempt === 0 && lockOwnerIsGone(lockPath)) {
7482
- fs11.rmSync(lockPath, { force: true });
7708
+ fs12.rmSync(lockPath, { force: true });
7483
7709
  continue;
7484
7710
  }
7485
7711
  throw new Error(
@@ -7492,7 +7718,7 @@ function acquireRunLock(stagingRoot) {
7492
7718
  function lockKeyFor(stagingRoot) {
7493
7719
  let key = stagingRoot;
7494
7720
  try {
7495
- key = fs11.realpathSync(stagingRoot);
7721
+ key = fs12.realpathSync(stagingRoot);
7496
7722
  } catch {
7497
7723
  }
7498
7724
  if (process.platform === "win32" || process.platform === "darwin") key = key.toLowerCase();
@@ -7501,7 +7727,7 @@ function lockKeyFor(stagingRoot) {
7501
7727
  function lockOwnerIsGone(lockPath) {
7502
7728
  let raw;
7503
7729
  try {
7504
- raw = fs11.readFileSync(lockPath, "utf8");
7730
+ raw = fs12.readFileSync(lockPath, "utf8");
7505
7731
  } catch {
7506
7732
  return false;
7507
7733
  }
@@ -7521,12 +7747,12 @@ function lockOwnerIsGone(lockPath) {
7521
7747
  }
7522
7748
  function writeManifestAtomically(manifestPath, manifest) {
7523
7749
  const tempPath = `${manifestPath}.${process.pid}.tmp`;
7524
- fs11.writeFileSync(tempPath, JSON.stringify(manifest, null, 2), "utf8");
7750
+ fs12.writeFileSync(tempPath, JSON.stringify(manifest, null, 2), "utf8");
7525
7751
  try {
7526
- fs11.renameSync(tempPath, manifestPath);
7752
+ fs12.renameSync(tempPath, manifestPath);
7527
7753
  } catch (err) {
7528
7754
  try {
7529
- fs11.rmSync(tempPath, { force: true });
7755
+ fs12.rmSync(tempPath, { force: true });
7530
7756
  } catch {
7531
7757
  }
7532
7758
  throw err;
@@ -7549,31 +7775,31 @@ function swapIntoPlace(stagingDir, outDir) {
7549
7775
  }
7550
7776
  function swapOnce(stagingDir, outDir) {
7551
7777
  const backupDir = `${outDir}.backup-${process.pid}-${Date.now()}`;
7552
- const hadPrevious = fs11.existsSync(outDir);
7553
- if (hadPrevious) fs11.renameSync(outDir, backupDir);
7778
+ const hadPrevious = fs12.existsSync(outDir);
7779
+ if (hadPrevious) fs12.renameSync(outDir, backupDir);
7554
7780
  try {
7555
7781
  try {
7556
- fs11.renameSync(stagingDir, outDir);
7782
+ fs12.renameSync(stagingDir, outDir);
7557
7783
  } catch (err) {
7558
7784
  if (err.code !== "EXDEV") throw err;
7559
7785
  const partialDir = `${outDir}.partial-${process.pid}-${Date.now()}`;
7560
7786
  try {
7561
- fs11.cpSync(stagingDir, partialDir, { recursive: true });
7562
- fs11.renameSync(partialDir, outDir);
7563
- fs11.rmSync(stagingDir, { recursive: true, force: true });
7787
+ fs12.cpSync(stagingDir, partialDir, { recursive: true });
7788
+ fs12.renameSync(partialDir, outDir);
7789
+ fs12.rmSync(stagingDir, { recursive: true, force: true });
7564
7790
  } catch (copyErr) {
7565
7791
  try {
7566
- fs11.rmSync(partialDir, { recursive: true, force: true });
7792
+ fs12.rmSync(partialDir, { recursive: true, force: true });
7567
7793
  } catch {
7568
7794
  }
7569
7795
  throw copyErr;
7570
7796
  }
7571
7797
  }
7572
- if (hadPrevious) fs11.rmSync(backupDir, { recursive: true, force: true });
7798
+ if (hadPrevious) fs12.rmSync(backupDir, { recursive: true, force: true });
7573
7799
  } catch (err) {
7574
- if (hadPrevious && fs11.existsSync(backupDir)) {
7575
- if (fs11.existsSync(outDir)) fs11.rmSync(outDir, { recursive: true, force: true });
7576
- fs11.renameSync(backupDir, outDir);
7800
+ if (hadPrevious && fs12.existsSync(backupDir)) {
7801
+ if (fs12.existsSync(outDir)) fs12.rmSync(outDir, { recursive: true, force: true });
7802
+ fs12.renameSync(backupDir, outDir);
7577
7803
  }
7578
7804
  throw err;
7579
7805
  }
@@ -7668,7 +7894,7 @@ function generateSnapshot(configInput, options) {
7668
7894
  // first run cannot have marked them yet, so the name alone keeps a run from recording its own
7669
7895
  // output — but only at these exact paths, not at every directory that shares the name.
7670
7896
  toolOwnedPaths: [config.outDir, config.tmpDir].map(
7671
- (directory) => path12.relative(config.cwd, path12.resolve(config.cwd, directory)).replace(/\\/g, "/")
7897
+ (directory) => path13.relative(config.cwd, path13.resolve(config.cwd, directory)).replace(/\\/g, "/")
7672
7898
  ).filter((relative11) => relative11.length > 0 && !relative11.startsWith(".."))
7673
7899
  });
7674
7900
  const files = [];
@@ -7689,12 +7915,12 @@ function generateSnapshot(configInput, options) {
7689
7915
  let totalSizeBytes = 0;
7690
7916
  let largeFileCount = 0;
7691
7917
  for (const relativePath of collection.files) {
7692
- const absolutePath = path12.join(config.cwd, relativePath);
7918
+ const absolutePath = path13.join(config.cwd, relativePath);
7693
7919
  let stats;
7694
7920
  try {
7695
- stats = fs11.statSync(absolutePath);
7921
+ stats = fs12.statSync(absolutePath);
7696
7922
  if (!stats.isFile()) {
7697
- const nestedRepository = stats.isDirectory() && fs11.existsSync(path12.join(absolutePath, ".git"));
7923
+ const nestedRepository = stats.isDirectory() && fs12.existsSync(path13.join(absolutePath, ".git"));
7698
7924
  skipped.push(
7699
7925
  nestedRepository ? {
7700
7926
  path: relativePath,
@@ -7714,7 +7940,7 @@ function generateSnapshot(configInput, options) {
7714
7940
  }
7715
7941
  let buffer;
7716
7942
  try {
7717
- buffer = fs11.readFileSync(absolutePath);
7943
+ buffer = fs12.readFileSync(absolutePath);
7718
7944
  } catch {
7719
7945
  skipped.push({ path: relativePath, reason: "read-error" });
7720
7946
  continue;
@@ -8044,12 +8270,12 @@ function generateSnapshot(configInput, options) {
8044
8270
  let stagingDir = null;
8045
8271
  try {
8046
8272
  ensureParentDirectory(outDir, "outDir");
8047
- fs11.mkdirSync(tmpDir, { recursive: true });
8273
+ fs12.mkdirSync(tmpDir, { recursive: true });
8048
8274
  cleanStaleRunDirs(tmpDir);
8049
8275
  const snapshotId = crypto3.randomUUID();
8050
8276
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
8051
- stagingDir = path12.join(tmpDir, `${RUN_DIR_PREFIX}${process.pid}-${snapshotId.slice(0, 8)}`);
8052
- fs11.mkdirSync(stagingDir);
8277
+ stagingDir = path13.join(tmpDir, `${RUN_DIR_PREFIX}${process.pid}-${snapshotId.slice(0, 8)}`);
8278
+ fs12.mkdirSync(stagingDir);
8053
8279
  writeOwnershipMarker(stagingDir, {
8054
8280
  generator: GENERATOR_NAME,
8055
8281
  version: GENERATOR_VERSION,
@@ -8059,41 +8285,41 @@ function generateSnapshot(configInput, options) {
8059
8285
  id: snapshotId,
8060
8286
  pid: process.pid
8061
8287
  });
8062
- const partsDir = path12.join(stagingDir, "parts");
8063
- const reportsDir = path12.join(stagingDir, "reports");
8064
- if (artifacts.parts) fs11.mkdirSync(partsDir, { recursive: true });
8288
+ const partsDir = path13.join(stagingDir, "parts");
8289
+ const reportsDir = path13.join(stagingDir, "reports");
8290
+ if (artifacts.parts) fs12.mkdirSync(partsDir, { recursive: true });
8065
8291
  if (artifacts.navigation || artifacts.projectTree || artifacts.audit) {
8066
- fs11.mkdirSync(reportsDir, { recursive: true });
8292
+ fs12.mkdirSync(reportsDir, { recursive: true });
8067
8293
  }
8068
8294
  if (artifacts.parts) {
8069
8295
  for (const part of parts) {
8070
- fs11.writeFileSync(path12.join(partsDir, part.filename), part.markdown, "utf8");
8296
+ fs12.writeFileSync(path13.join(partsDir, part.filename), part.markdown, "utf8");
8071
8297
  }
8072
8298
  }
8073
8299
  if (projectTree !== null) {
8074
- fs11.writeFileSync(path12.join(reportsDir, "project-tree.md"), projectTree, "utf8");
8300
+ fs12.writeFileSync(path13.join(reportsDir, "project-tree.md"), projectTree, "utf8");
8075
8301
  }
8076
8302
  if (artifacts.navigation) {
8077
- fs11.writeFileSync(path12.join(reportsDir, "navigation.md"), generateNavigation(manifest), "utf8");
8303
+ fs12.writeFileSync(path13.join(reportsDir, "navigation.md"), generateNavigation(manifest), "utf8");
8078
8304
  }
8079
8305
  if (artifacts.audit) {
8080
- fs11.writeFileSync(
8081
- path12.join(reportsDir, "audit.md"),
8306
+ fs12.writeFileSync(
8307
+ path13.join(reportsDir, "audit.md"),
8082
8308
  generateAuditReport(manifest, secretFindings, config.secretRules),
8083
8309
  "utf8"
8084
8310
  );
8085
8311
  }
8086
8312
  if (artifacts.readme) {
8087
- fs11.writeFileSync(path12.join(stagingDir, "README.md"), generateReadme(manifest, artifacts), "utf8");
8313
+ fs12.writeFileSync(path13.join(stagingDir, "README.md"), generateReadme(manifest, artifacts), "utf8");
8088
8314
  }
8089
8315
  if (artifacts.manifest) {
8090
- fs11.writeFileSync(path12.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
8316
+ fs12.writeFileSync(path13.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
8091
8317
  }
8092
8318
  if (monolithJson !== null) {
8093
- fs11.writeFileSync(path12.join(stagingDir, "full-codebase.json"), monolithJson, "utf8");
8319
+ fs12.writeFileSync(path13.join(stagingDir, "full-codebase.json"), monolithJson, "utf8");
8094
8320
  }
8095
8321
  if (monolithMarkdown !== null) {
8096
- fs11.writeFileSync(path12.join(stagingDir, "full-codebase.md"), monolithMarkdown, "utf8");
8322
+ fs12.writeFileSync(path13.join(stagingDir, "full-codebase.md"), monolithMarkdown, "utf8");
8097
8323
  }
8098
8324
  writeOwnershipMarker(stagingDir, markerPayload(stagingDir, "complete", snapshotId, createdAt));
8099
8325
  swapIntoPlace(stagingDir, outDir);
@@ -8102,7 +8328,7 @@ function generateSnapshot(configInput, options) {
8102
8328
  const pendingHook = runAfterGenerate(config, manifest);
8103
8329
  const shipHookState = () => {
8104
8330
  if (artifacts.manifest && manifest.warnings.length !== warningsBeforeHook) {
8105
- writeManifestAtomically(path12.join(outDir, "manifest.json"), manifest);
8331
+ writeManifestAtomically(path13.join(outDir, "manifest.json"), manifest);
8106
8332
  }
8107
8333
  writeOwnershipMarker(outDir, markerPayload(outDir, "complete", snapshotId, createdAt));
8108
8334
  };
@@ -8125,7 +8351,7 @@ function generateSnapshot(configInput, options) {
8125
8351
  } catch (err) {
8126
8352
  if (stagingDir !== null) {
8127
8353
  try {
8128
- fs11.rmSync(stagingDir, { recursive: true, force: true });
8354
+ fs12.rmSync(stagingDir, { recursive: true, force: true });
8129
8355
  } catch {
8130
8356
  }
8131
8357
  }
@@ -8137,8 +8363,8 @@ function generateSnapshot(configInput, options) {
8137
8363
  }
8138
8364
 
8139
8365
  // src/mcp/tools.ts
8140
- import * as fs13 from "fs";
8141
- import * as path14 from "path";
8366
+ import * as fs14 from "fs";
8367
+ import * as path15 from "path";
8142
8368
 
8143
8369
  // src/mcp/part.ts
8144
8370
  var FILE_HEADING = "### FILE: ";
@@ -8224,15 +8450,15 @@ function windowText(body, fromLine, lineCount) {
8224
8450
  }
8225
8451
 
8226
8452
  // src/mcp/workspace.ts
8227
- import * as fs12 from "fs";
8228
- import * as path13 from "path";
8453
+ import * as fs13 from "fs";
8454
+ import * as path14 from "path";
8229
8455
  function foldForComparison(value) {
8230
8456
  return process.platform === "win32" || process.platform === "darwin" ? value.toLowerCase() : value;
8231
8457
  }
8232
8458
  function canonicalPath(value) {
8233
- const absolute = path13.resolve(value);
8459
+ const absolute = path14.resolve(value);
8234
8460
  try {
8235
- return fs12.realpathSync(absolute);
8461
+ return fs13.realpathSync(absolute);
8236
8462
  } catch {
8237
8463
  return absolute;
8238
8464
  }
@@ -8240,17 +8466,17 @@ function canonicalPath(value) {
8240
8466
  function isInside2(parent, child) {
8241
8467
  const foldedParent = foldForComparison(parent);
8242
8468
  const foldedChild = foldForComparison(child);
8243
- return foldedChild === foldedParent || foldedChild.startsWith(`${foldedParent}${path13.sep}`);
8469
+ return foldedChild === foldedParent || foldedChild.startsWith(`${foldedParent}${path14.sep}`);
8244
8470
  }
8245
8471
  function resolveRoot(requested, context) {
8246
8472
  if (requested !== void 0 && (typeof requested !== "string" || requested.trim().length === 0)) {
8247
8473
  return { ok: false, message: '"root" must be a non-empty string when provided.' };
8248
8474
  }
8249
8475
  const wanted = typeof requested === "string" ? requested.trim() : context.cwd;
8250
- const absolute = path13.resolve(context.cwd, wanted);
8476
+ const absolute = path14.resolve(context.cwd, wanted);
8251
8477
  let stats;
8252
8478
  try {
8253
- stats = fs12.statSync(absolute);
8479
+ stats = fs13.statSync(absolute);
8254
8480
  } catch {
8255
8481
  return { ok: false, message: `"${wanted}" does not exist, so it cannot be a repository root.` };
8256
8482
  }
@@ -8301,14 +8527,14 @@ async function openWorkspace(root, overrides = {}) {
8301
8527
  }
8302
8528
  var manifestCache = /* @__PURE__ */ new Map();
8303
8529
  function manifestPathFor(workspace) {
8304
- return path13.resolve(workspace.root, workspace.config.outDir, "manifest.json");
8530
+ return path14.resolve(workspace.root, workspace.config.outDir, "manifest.json");
8305
8531
  }
8306
8532
  function readManifest3(workspace) {
8307
8533
  const file = manifestPathFor(workspace);
8308
- const shown = path13.relative(workspace.root, file).split(path13.sep).join("/") || file;
8534
+ const shown = path14.relative(workspace.root, file).split(path14.sep).join("/") || file;
8309
8535
  let stats;
8310
8536
  try {
8311
- stats = fs12.statSync(file);
8537
+ stats = fs13.statSync(file);
8312
8538
  } catch {
8313
8539
  return {
8314
8540
  ok: false,
@@ -8322,7 +8548,7 @@ function readManifest3(workspace) {
8322
8548
  }
8323
8549
  let raw;
8324
8550
  try {
8325
- raw = fs12.readFileSync(file, "utf8");
8551
+ raw = fs13.readFileSync(file, "utf8");
8326
8552
  } catch (error) {
8327
8553
  return {
8328
8554
  ok: false,
@@ -8380,7 +8606,7 @@ function formatBytes(bytes) {
8380
8606
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
8381
8607
  }
8382
8608
  function relativeFor(workspace, absolute) {
8383
- return path14.relative(workspace.root, absolute).split(path14.sep).join("/");
8609
+ return path15.relative(workspace.root, absolute).split(path15.sep).join("/");
8384
8610
  }
8385
8611
  function capped(values, limit = 20) {
8386
8612
  return { count: values.length, sample: values.slice(0, limit) };
@@ -8399,12 +8625,12 @@ function summarizeDrift(drift) {
8399
8625
  function toRelativePath(root, value) {
8400
8626
  const cleaned = value.trim();
8401
8627
  if (cleaned.length === 0) return null;
8402
- if (!path14.isAbsolute(cleaned)) {
8628
+ if (!path15.isAbsolute(cleaned)) {
8403
8629
  return cleaned.replace(/\\/g, "/").replace(/^\.\//, "");
8404
8630
  }
8405
- const relative11 = path14.relative(root, cleaned);
8406
- if (relative11.startsWith("..") || path14.isAbsolute(relative11)) return null;
8407
- return relative11.split(path14.sep).join("/");
8631
+ const relative11 = path15.relative(root, cleaned);
8632
+ if (relative11.startsWith("..") || path15.isAbsolute(relative11)) return null;
8633
+ return relative11.split(path15.sep).join("/");
8408
8634
  }
8409
8635
  function symbolsOf(entry) {
8410
8636
  const summary = entry.summary;
@@ -8615,7 +8841,7 @@ var generateTool = {
8615
8841
  return failure(error instanceof Error ? error.message : String(error));
8616
8842
  }
8617
8843
  forgetManifest(manifestPathFor(workspace));
8618
- const written = relativeFor(workspace, path14.resolve(workspace.root, workspace.config.outDir));
8844
+ const written = relativeFor(workspace, path15.resolve(workspace.root, workspace.config.outDir));
8619
8845
  const lines = [
8620
8846
  `Wrote ${written}/`,
8621
8847
  `Files: ${manifest.counts.totalFiles} included, ${manifest.counts.skippedCount} skipped, ${plural(manifest.counts.partsCount, "part")}`,
@@ -8880,10 +9106,10 @@ var readTool = {
8880
9106
  `${relativePath} is not in the snapshot. Call snapshot_locate to find the path, or snapshot_explain to learn why it was excluded.`
8881
9107
  );
8882
9108
  }
8883
- const partPath = path14.resolve(workspace.root, workspace.config.outDir, "parts", entry.part);
9109
+ const partPath = path15.resolve(workspace.root, workspace.config.outDir, "parts", entry.part);
8884
9110
  let partText;
8885
9111
  try {
8886
- partText = fs13.readFileSync(partPath, "utf8");
9112
+ partText = fs14.readFileSync(partPath, "utf8");
8887
9113
  } catch {
8888
9114
  return failure(
8889
9115
  `${entry.part} could not be read, so the snapshot is damaged. Run snapshot_generate to rebuild it.`
@@ -9145,6 +9371,7 @@ var VALIDATE_OPTIONS = [
9145
9371
  "no-config",
9146
9372
  "discovery",
9147
9373
  "format",
9374
+ "no-update-check",
9148
9375
  "mode",
9149
9376
  "help",
9150
9377
  "version"
@@ -9168,6 +9395,7 @@ var COMMAND_OPTION_SCOPE = {
9168
9395
  "watch",
9169
9396
  "autopilot",
9170
9397
  "no-install",
9398
+ "no-update-check",
9171
9399
  "help",
9172
9400
  "version"
9173
9401
  ],
@@ -9183,6 +9411,7 @@ var COMMAND_OPTION_SCOPE = {
9183
9411
  "skip-artifacts",
9184
9412
  "only-artifacts",
9185
9413
  "no-config",
9414
+ "no-update-check",
9186
9415
  "format",
9187
9416
  "mode",
9188
9417
  "help",
@@ -9200,12 +9429,13 @@ var COMMAND_OPTION_SCOPE = {
9200
9429
  "only-artifacts",
9201
9430
  "no-config",
9202
9431
  "discovery",
9432
+ "no-update-check",
9203
9433
  "format",
9204
9434
  "mode",
9205
9435
  "help",
9206
9436
  "version"
9207
9437
  ],
9208
- diff: ["format", "mode", "no-config", "help", "version"],
9438
+ diff: ["format", "mode", "no-config", "no-update-check", "help", "version"],
9209
9439
  describe: ["format", "mode", "help", "version"],
9210
9440
  init: [
9211
9441
  "cwd",
@@ -9220,6 +9450,7 @@ var COMMAND_OPTION_SCOPE = {
9220
9450
  "yes",
9221
9451
  "force",
9222
9452
  "dry-run",
9453
+ "no-update-check",
9223
9454
  "format",
9224
9455
  "mode",
9225
9456
  "help",
@@ -9243,6 +9474,7 @@ var COMMAND_OPTION_SCOPE = {
9243
9474
  "force",
9244
9475
  "no-install",
9245
9476
  "dry-run",
9477
+ "no-update-check",
9246
9478
  "format",
9247
9479
  "mode",
9248
9480
  "help",
@@ -9675,6 +9907,13 @@ function buildAgentContract() {
9675
9907
  default: false,
9676
9908
  appliesTo: optionAppliesTo("no-install"),
9677
9909
  summary: "Skip installing the dependency before generating: `setup`, or `generate --autopilot` (CI, offline, or a lockfile you do not want a package manager to touch)."
9910
+ },
9911
+ {
9912
+ flag: "--no-update-check",
9913
+ type: "boolean",
9914
+ default: false,
9915
+ appliesTo: optionAppliesTo("no-update-check"),
9916
+ summary: "Skip the once-a-day check for a newer published version. The check is already skipped when stdout is not a terminal, in CI, in a JSON invocation, and in `mcp`, which makes no network requests."
9678
9917
  }
9679
9918
  ],
9680
9919
  presets: PRESETS.map((preset) => ({
@@ -9807,8 +10046,8 @@ function buildAgentContract() {
9807
10046
  }
9808
10047
 
9809
10048
  // src/agent/install-skill.ts
9810
- import * as fs14 from "fs";
9811
- import * as path15 from "path";
10049
+ import * as fs15 from "fs";
10050
+ import * as path16 from "path";
9812
10051
 
9813
10052
  // src/agent/skill.ts
9814
10053
  var PACKAGE_NAME2 = "codebase-snapshot";
@@ -9966,17 +10205,17 @@ var LEGACY_AGENTS_MARKER = "<!-- codebase-snapshot:skill:start -->";
9966
10205
  function targetPath(cwd, target) {
9967
10206
  switch (target) {
9968
10207
  case "claude":
9969
- return path15.join(cwd, ".claude", "skills", SKILL_NAME, "SKILL.md");
10208
+ return path16.join(cwd, ".claude", "skills", SKILL_NAME, "SKILL.md");
9970
10209
  case "cursor":
9971
- return path15.join(cwd, ".cursor", "rules", `${SKILL_NAME}.mdc`);
10210
+ return path16.join(cwd, ".cursor", "rules", `${SKILL_NAME}.mdc`);
9972
10211
  }
9973
10212
  }
9974
10213
  function assertWritableInsideRepository(cwd, filePath) {
9975
- const root = fs14.realpathSync(cwd);
9976
- const shown = path15.relative(root, filePath) || filePath;
10214
+ const root = fs15.realpathSync(cwd);
10215
+ const shown = path16.relative(root, filePath) || filePath;
9977
10216
  let stat = null;
9978
10217
  try {
9979
- stat = fs14.lstatSync(filePath);
10218
+ stat = fs15.lstatSync(filePath);
9980
10219
  } catch {
9981
10220
  stat = null;
9982
10221
  }
@@ -9992,32 +10231,32 @@ function assertWritableInsideRepository(cwd, filePath) {
9992
10231
  }
9993
10232
  let existing = filePath;
9994
10233
  const missing = [];
9995
- while (!fs14.existsSync(existing)) {
9996
- missing.unshift(path15.basename(existing));
9997
- const parent = path15.dirname(existing);
10234
+ while (!fs15.existsSync(existing)) {
10235
+ missing.unshift(path16.basename(existing));
10236
+ const parent = path16.dirname(existing);
9998
10237
  if (parent === existing) break;
9999
10238
  existing = parent;
10000
10239
  }
10001
- const realAncestor = fs14.realpathSync(existing);
10002
- const resolved = missing.length === 0 ? realAncestor : path15.join(realAncestor, ...missing);
10003
- if (resolved !== root && !resolved.startsWith(`${root}${path15.sep}`)) {
10240
+ const realAncestor = fs15.realpathSync(existing);
10241
+ const resolved = missing.length === 0 ? realAncestor : path16.join(realAncestor, ...missing);
10242
+ if (resolved !== root && !resolved.startsWith(`${root}${path16.sep}`)) {
10004
10243
  throw new Error(
10005
10244
  `${REFUSED}: ${shown} resolves outside the repository (${resolved}). Move it back inside ${root}, or remove the link, and run again.`
10006
10245
  );
10007
10246
  }
10008
10247
  }
10009
10248
  function writeIfChanged(target, filePath, content) {
10010
- const existing = fs14.existsSync(filePath) ? fs14.readFileSync(filePath, "utf8") : null;
10249
+ const existing = fs15.existsSync(filePath) ? fs15.readFileSync(filePath, "utf8") : null;
10011
10250
  if (existing === content) return { target, path: filePath, action: "unchanged" };
10012
- fs14.mkdirSync(path15.dirname(filePath), { recursive: true });
10013
- fs14.writeFileSync(filePath, content, "utf8");
10251
+ fs15.mkdirSync(path16.dirname(filePath), { recursive: true });
10252
+ fs15.writeFileSync(filePath, content, "utf8");
10014
10253
  return { target, path: filePath, action: existing === null ? "created" : "updated" };
10015
10254
  }
10016
10255
  function legacyAgentsNote(cwd) {
10017
- const filePath = path15.join(cwd, "AGENTS.md");
10256
+ const filePath = path16.join(cwd, "AGENTS.md");
10018
10257
  try {
10019
- if (!fs14.existsSync(filePath)) return null;
10020
- if (!fs14.readFileSync(filePath, "utf8").includes(LEGACY_AGENTS_MARKER)) return null;
10258
+ if (!fs15.existsSync(filePath)) return null;
10259
+ if (!fs15.readFileSync(filePath, "utf8").includes(LEGACY_AGENTS_MARKER)) return null;
10021
10260
  } catch {
10022
10261
  return null;
10023
10262
  }
@@ -10029,9 +10268,9 @@ function installSkill(cwd, target = "all") {
10029
10268
  const notes = [];
10030
10269
  const wanted = target === "all" ? ["claude", "cursor"] : [target];
10031
10270
  for (const item of wanted) assertWritableInsideRepository(cwd, targetPath(cwd, item));
10032
- const createsSomething = wanted.some((item) => !fs14.existsSync(targetPath(cwd, item)));
10271
+ const createsSomething = wanted.some((item) => !fs15.existsSync(targetPath(cwd, item)));
10033
10272
  if (createsSomething) {
10034
- assertWritableInsideRepository(cwd, path15.join(cwd, ".gitignore"));
10273
+ assertWritableInsideRepository(cwd, path16.join(cwd, ".gitignore"));
10035
10274
  }
10036
10275
  for (const item of wanted) {
10037
10276
  written.push(writeIfChanged(item, targetPath(cwd, item), skill));
@@ -10166,52 +10405,52 @@ function validateArguments(schema, value) {
10166
10405
  }
10167
10406
  return problems;
10168
10407
  }
10169
- function checkValue(path18, schema, value) {
10408
+ function checkValue(path19, schema, value) {
10170
10409
  if (schema.enum && !schema.enum.includes(value)) {
10171
- return [`"${path18}" must be one of: ${schema.enum.join(", ")}`];
10410
+ return [`"${path19}" must be one of: ${schema.enum.join(", ")}`];
10172
10411
  }
10173
10412
  switch (schema.type) {
10174
10413
  case "string": {
10175
- if (typeof value !== "string") return [`"${path18}" must be a string`];
10414
+ if (typeof value !== "string") return [`"${path19}" must be a string`];
10176
10415
  const problems = [];
10177
10416
  if (schema.minLength !== void 0 && value.length < schema.minLength) {
10178
- problems.push(`"${path18}" must be at least ${schema.minLength} character(s)`);
10417
+ problems.push(`"${path19}" must be at least ${schema.minLength} character(s)`);
10179
10418
  }
10180
10419
  if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
10181
- problems.push(`"${path18}" must be at most ${schema.maxLength} character(s)`);
10420
+ problems.push(`"${path19}" must be at most ${schema.maxLength} character(s)`);
10182
10421
  }
10183
10422
  return problems;
10184
10423
  }
10185
10424
  case "number":
10186
10425
  case "integer": {
10187
10426
  if (typeof value !== "number" || Number.isNaN(value)) {
10188
- return [`"${path18}" must be a number`];
10427
+ return [`"${path19}" must be a number`];
10189
10428
  }
10190
10429
  if (schema.type === "integer" && !Number.isInteger(value)) {
10191
- return [`"${path18}" must be an integer`];
10430
+ return [`"${path19}" must be an integer`];
10192
10431
  }
10193
10432
  const problems = [];
10194
10433
  if (schema.minimum !== void 0 && value < schema.minimum) {
10195
- problems.push(`"${path18}" must be >= ${schema.minimum}`);
10434
+ problems.push(`"${path19}" must be >= ${schema.minimum}`);
10196
10435
  }
10197
10436
  if (schema.maximum !== void 0 && value > schema.maximum) {
10198
- problems.push(`"${path18}" must be <= ${schema.maximum}`);
10437
+ problems.push(`"${path19}" must be <= ${schema.maximum}`);
10199
10438
  }
10200
10439
  return problems;
10201
10440
  }
10202
10441
  case "boolean":
10203
- return typeof value === "boolean" ? [] : [`"${path18}" must be a boolean`];
10442
+ return typeof value === "boolean" ? [] : [`"${path19}" must be a boolean`];
10204
10443
  case "array": {
10205
- if (!Array.isArray(value)) return [`"${path18}" must be an array`];
10444
+ if (!Array.isArray(value)) return [`"${path19}" must be an array`];
10206
10445
  if (!schema.items) return [];
10207
10446
  const problems = [];
10208
10447
  value.forEach((item, index) => {
10209
- problems.push(...checkValue(`${path18}[${index}]`, schema.items, item));
10448
+ problems.push(...checkValue(`${path19}[${index}]`, schema.items, item));
10210
10449
  });
10211
10450
  return problems;
10212
10451
  }
10213
10452
  case "object":
10214
- return isJsonObject(value) ? [] : [`"${path18}" must be an object`];
10453
+ return isJsonObject(value) ? [] : [`"${path19}" must be an object`];
10215
10454
  default:
10216
10455
  return [];
10217
10456
  }
@@ -10225,6 +10464,18 @@ function applyDefaults(schema, value) {
10225
10464
  }
10226
10465
  return out;
10227
10466
  }
10467
+ function coerceNumericStrings(schema, value) {
10468
+ const out = { ...value };
10469
+ for (const [key, propertySchema] of Object.entries(schema.properties)) {
10470
+ const raw = out[key];
10471
+ if (typeof raw !== "string") continue;
10472
+ if (propertySchema.type !== "number" && propertySchema.type !== "integer") continue;
10473
+ if (raw.trim().length === 0) continue;
10474
+ const parsed = Number(raw);
10475
+ if (Number.isFinite(parsed)) out[key] = parsed;
10476
+ }
10477
+ return out;
10478
+ }
10228
10479
 
10229
10480
  // src/mcp/server.ts
10230
10481
  function capabilities() {
@@ -10313,7 +10564,8 @@ function createMcpServer(options) {
10313
10564
  if (!isJsonObject(rawArguments)) {
10314
10565
  return errorResponse(id, ERROR_CODES.invalidParams, '"arguments" must be a JSON object.');
10315
10566
  }
10316
- const problems = validateArguments(tool.inputSchema, rawArguments);
10567
+ const supplied = coerceNumericStrings(tool.inputSchema, rawArguments);
10568
+ const problems = validateArguments(tool.inputSchema, supplied);
10317
10569
  if (problems.length > 0) {
10318
10570
  return ok(
10319
10571
  id,
@@ -10325,7 +10577,7 @@ function createMcpServer(options) {
10325
10577
  modern
10326
10578
  );
10327
10579
  }
10328
- const args = applyDefaults(tool.inputSchema, rawArguments);
10580
+ const args = applyDefaults(tool.inputSchema, supplied);
10329
10581
  let outcome;
10330
10582
  try {
10331
10583
  outcome = await tool.handler(args, options.context);
@@ -10494,8 +10746,8 @@ function createMcpServer(options) {
10494
10746
  }
10495
10747
 
10496
10748
  // src/mcp/resources.ts
10497
- import * as fs15 from "fs";
10498
- import * as path16 from "path";
10749
+ import * as fs16 from "fs";
10750
+ import * as path17 from "path";
10499
10751
  var MAX_RESOURCE_BYTES = 512 * 1024;
10500
10752
  var PART_URI = /^snapshot:\/\/parts\/(\d+)$/;
10501
10753
  var REPORT_URIS = /* @__PURE__ */ new Map([
@@ -10529,7 +10781,7 @@ async function workspaceFor(context) {
10529
10781
  }
10530
10782
  function readFileIfPresent(file) {
10531
10783
  try {
10532
- return fs15.readFileSync(file, "utf8");
10784
+ return fs16.readFileSync(file, "utf8");
10533
10785
  } catch {
10534
10786
  return null;
10535
10787
  }
@@ -10608,7 +10860,7 @@ function buildResourceProvider() {
10608
10860
  const report = REPORT_URIS.get(uri);
10609
10861
  if (report) {
10610
10862
  const text2 = readFileIfPresent(
10611
- path16.resolve(workspace.root, workspace.config.outDir, "reports", report.file)
10863
+ path17.resolve(workspace.root, workspace.config.outDir, "reports", report.file)
10612
10864
  );
10613
10865
  if (text2 === null) return null;
10614
10866
  return { uri, mimeType: "text/markdown", text: capUtf8(text2, MAX_RESOURCE_BYTES).text };
@@ -10627,7 +10879,7 @@ function buildResourceProvider() {
10627
10879
  const part = read.manifest.parts.find((candidate) => candidate.index === index);
10628
10880
  if (!part) return null;
10629
10881
  const text2 = readFileIfPresent(
10630
- path16.resolve(workspace.root, workspace.config.outDir, "parts", part.filename)
10882
+ path17.resolve(workspace.root, workspace.config.outDir, "parts", part.filename)
10631
10883
  );
10632
10884
  if (text2 === null) return null;
10633
10885
  return { uri, mimeType: "text/markdown", text: capUtf8(text2, MAX_RESOURCE_BYTES).text };
@@ -10865,6 +11117,7 @@ var CLI_OPTIONS = {
10865
11117
  install: { type: "boolean" },
10866
11118
  "no-install": { type: "boolean" },
10867
11119
  target: { type: "string" },
11120
+ "no-update-check": { type: "boolean" },
10868
11121
  help: { type: "boolean", short: "h" },
10869
11122
  version: { type: "boolean", short: "v" }
10870
11123
  };
@@ -10939,6 +11192,8 @@ Options:
10939
11192
  --install Write the skill into the repository instead of printing
10940
11193
  --target <name> claude | cursor | all (default: all)
10941
11194
 
11195
+ --no-update-check Skip the daily check for a newer published version
11196
+
10942
11197
  -h, --help Display this help message
10943
11198
  -v, --version Display version
10944
11199
 
@@ -11003,10 +11258,10 @@ function parseCliArgs(argv) {
11003
11258
  }
11004
11259
  if (values.cwd !== void 0) {
11005
11260
  const target = String(values.cwd);
11006
- if (!fs16.existsSync(target)) {
11261
+ if (!fs17.existsSync(target)) {
11007
11262
  throw new UsageError(`--cwd directory does not exist: ${target}`);
11008
11263
  }
11009
- if (!fs16.statSync(target).isDirectory()) {
11264
+ if (!fs17.statSync(target).isDirectory()) {
11010
11265
  throw new UsageError(`--cwd is not a directory: ${target}`);
11011
11266
  }
11012
11267
  }
@@ -11152,7 +11407,7 @@ function parseCliArgs(argv) {
11152
11407
  install: values.install === true,
11153
11408
  noInstall: values["no-install"] === true,
11154
11409
  target: values.target === void 0 ? void 0 : String(values.target),
11155
- cwd: values.cwd === void 0 ? process.cwd() : path17.resolve(String(values.cwd)),
11410
+ cwd: values.cwd === void 0 ? process.cwd() : path18.resolve(String(values.cwd)),
11156
11411
  outDir: values["out-dir"] === void 0 ? void 0 : String(values["out-dir"]),
11157
11412
  includeMonolith: values["include-monolith"] === true || onlyNamesMonolith === true ? true : void 0,
11158
11413
  includeSensitiveFiles: values["include-sensitive-files"] === true ? true : void 0,
@@ -11209,24 +11464,24 @@ function splitList(value) {
11209
11464
  return value.split(",").map((entry) => entry.trim()).filter(Boolean);
11210
11465
  }
11211
11466
  function displayOutPath(cwd, outDir, ...segments) {
11212
- const absolute = path17.resolve(cwd, outDir, ...segments);
11213
- const relative11 = path17.relative(cwd, absolute);
11214
- if (relative11 && !relative11.startsWith("..") && !path17.isAbsolute(relative11)) return relative11;
11467
+ const absolute = path18.resolve(cwd, outDir, ...segments);
11468
+ const relative11 = path18.relative(cwd, absolute);
11469
+ if (relative11 && !relative11.startsWith("..") && !path18.isAbsolute(relative11)) return relative11;
11215
11470
  return absolute;
11216
11471
  }
11217
11472
  function nextStepHint(cwd, scriptsAddedNow) {
11218
11473
  let hasScript = scriptsAddedNow;
11219
11474
  if (!hasScript) {
11220
11475
  try {
11221
- const parsed = JSON.parse(fs16.readFileSync(path17.join(cwd, "package.json"), "utf8"));
11476
+ const parsed = JSON.parse(fs17.readFileSync(path18.join(cwd, "package.json"), "utf8"));
11222
11477
  hasScript = typeof parsed.scripts?.snapshot === "string";
11223
11478
  } catch {
11224
11479
  hasScript = false;
11225
11480
  }
11226
11481
  }
11227
11482
  if (!hasScript) return `npx ${GENERATOR_NAME} generate`;
11228
- const bin = path17.join(cwd, "node_modules", ".bin", "codebase-snapshot");
11229
- const installed = fs16.existsSync(bin) || fs16.existsSync(`${bin}.cmd`);
11483
+ const bin = path18.join(cwd, "node_modules", ".bin", "codebase-snapshot");
11484
+ const installed = fs17.existsSync(bin) || fs17.existsSync(`${bin}.cmd`);
11230
11485
  return installed ? "npm run snapshot" : "npm install && npm run snapshot";
11231
11486
  }
11232
11487
  function presetSummary(init) {
@@ -11256,7 +11511,7 @@ async function runInitCommand(invocation) {
11256
11511
  info(result.configText);
11257
11512
  return 0;
11258
11513
  }
11259
- info(`\u2705 Created ${path17.basename(result.configPath)} (${presetSummary(result)})`);
11514
+ info(`\u2705 Created ${path18.basename(result.configPath)} (${presetSummary(result)})`);
11260
11515
  if (result.scripts.length > 0) info(` Added npm scripts: ${result.scripts.join(", ")}`);
11261
11516
  if (result.dependency.added && result.dependency.range !== null) {
11262
11517
  info(` Added devDependency: ${result.dependency.name} ${result.dependency.range}`);
@@ -11276,7 +11531,7 @@ async function runInitCommand(invocation) {
11276
11531
  }
11277
11532
  }
11278
11533
  function detectPackageManager(cwd) {
11279
- const has = (name) => fs16.existsSync(path17.join(cwd, name));
11534
+ const has = (name) => fs17.existsSync(path18.join(cwd, name));
11280
11535
  if (has("bun.lockb") || has("bun.lock")) return { name: "bun", command: "bun", args: ["install"] };
11281
11536
  if (has("pnpm-lock.yaml")) return { name: "pnpm", command: "pnpm", args: ["install"] };
11282
11537
  if (has("yarn.lock")) return { name: "yarn", command: "yarn", args: ["install"] };
@@ -11365,7 +11620,7 @@ async function runSetupCommand(invocation, options = {}) {
11365
11620
  }
11366
11621
  info("\n\u{1F9EA} Dry run \u2014 setup would:");
11367
11622
  info(
11368
- ` 1. ${init.reused ? `keep ${path17.basename(init.configPath)}` : `write ${path17.basename(init.configPath)} (preset: ${init.preset})`}`
11623
+ ` 1. ${init.reused ? `keep ${path18.basename(init.configPath)}` : `write ${path18.basename(init.configPath)} (preset: ${init.preset})`}`
11369
11624
  );
11370
11625
  info(" 2. add the npm scripts, the devDependency and the .gitignore entries");
11371
11626
  if (manager !== null) info(` 3. install with ${manager}`);
@@ -11377,9 +11632,9 @@ async function runSetupCommand(invocation, options = {}) {
11377
11632
  if (invocation.format !== "json") {
11378
11633
  if (!interactive) info(`\u{1F680} Setup for: ${invocation.cwd}`);
11379
11634
  if (init.reused) {
11380
- info(`\u267B Keeping ${path17.basename(init.configPath)} (${presetSummary(init)})`);
11635
+ info(`\u267B Keeping ${path18.basename(init.configPath)} (${presetSummary(init)})`);
11381
11636
  } else {
11382
- info(`\u2705 Created ${path17.basename(init.configPath)} (${presetSummary(init)})`);
11637
+ info(`\u2705 Created ${path18.basename(init.configPath)} (${presetSummary(init)})`);
11383
11638
  }
11384
11639
  if (init.scripts.length > 0) info(` Added npm scripts: ${init.scripts.join(", ")}`);
11385
11640
  if (init.dependency.added && init.dependency.range !== null) {
@@ -11487,7 +11742,7 @@ function runSkillCommand(invocation) {
11487
11742
  }
11488
11743
  info(`\u2705 Agent skill installed (${SKILL_NAME}):`);
11489
11744
  for (const item of result.written) {
11490
- const shown = path17.relative(invocation.cwd, item.path) || item.path;
11745
+ const shown = path18.relative(invocation.cwd, item.path) || item.path;
11491
11746
  info(` - ${item.action.padEnd(9)} ${shown}`);
11492
11747
  }
11493
11748
  if (result.gitignored.length > 0) {
@@ -11551,6 +11806,17 @@ function requestsJsonFormat(argv) {
11551
11806
  return format === "json";
11552
11807
  }
11553
11808
  async function main(argv = process.argv.slice(2)) {
11809
+ const pending = process.stdout.isTTY === true && shouldCheck(argv, process.env) ? checkForUpdate({ current: GENERATOR_VERSION, cacheFile: cacheFilePath() }) : null;
11810
+ const code = await runCommand(argv);
11811
+ if (pending) {
11812
+ const notice = await pending;
11813
+ if (notice) process.stderr.write(`
11814
+ ${formatUpdateNotice(notice)}
11815
+ `);
11816
+ }
11817
+ return code;
11818
+ }
11819
+ async function runCommand(argv) {
11554
11820
  let invocation;
11555
11821
  try {
11556
11822
  invocation = parseCliArgs(argv);
@@ -11583,7 +11849,7 @@ ${USAGE}
11583
11849
  return runSkillCommand(invocation);
11584
11850
  }
11585
11851
  if (invocation.command === "mcp") {
11586
- return await runStdioServer({ cwd: path17.resolve(invocation.cwd) });
11852
+ return await runStdioServer({ cwd: path18.resolve(invocation.cwd) });
11587
11853
  }
11588
11854
  if (invocation.command === "setup") {
11589
11855
  return runSetupCommand(invocation);
@@ -11600,7 +11866,7 @@ ${USAGE}
11600
11866
  warn("\u274C The config file could not be read. Fix it, or delete it to use the defaults.");
11601
11867
  return 1;
11602
11868
  }
11603
- if (loaded.file) info(`\u2699 Using config ${path17.relative(process.cwd(), loaded.file) || loaded.file}`);
11869
+ if (loaded.file) info(`\u2699 Using config ${path18.relative(process.cwd(), loaded.file) || loaded.file}`);
11604
11870
  const resolved = resolveConfig(
11605
11871
  loaded.config,
11606
11872
  {
@@ -11622,10 +11888,10 @@ ${USAGE}
11622
11888
  if (invocation.command === "validate") {
11623
11889
  const result = validateSnapshot(resolved);
11624
11890
  if (result.valid) {
11625
- const manifestPath = path17.resolve(resolved.cwd, resolved.outDir, "manifest.json");
11891
+ const manifestPath = path18.resolve(resolved.cwd, resolved.outDir, "manifest.json");
11626
11892
  let manifest;
11627
11893
  try {
11628
- manifest = JSON.parse(fs16.readFileSync(manifestPath, "utf8"));
11894
+ manifest = JSON.parse(fs17.readFileSync(manifestPath, "utf8"));
11629
11895
  } catch {
11630
11896
  manifest = void 0;
11631
11897
  }
@@ -11638,13 +11904,13 @@ ${USAGE}
11638
11904
  return result.valid ? 0 : 1;
11639
11905
  }
11640
11906
  if (invocation.command === "report") {
11641
- const manifestPath = path17.resolve(resolved.cwd, resolved.outDir, "manifest.json");
11642
- if (!fs16.existsSync(manifestPath)) {
11907
+ const manifestPath = path18.resolve(resolved.cwd, resolved.outDir, "manifest.json");
11908
+ if (!fs17.existsSync(manifestPath)) {
11643
11909
  return fail(invocation.format, `Manifest not found at ${manifestPath}. Run generate first.`);
11644
11910
  }
11645
11911
  let manifest;
11646
11912
  try {
11647
- manifest = JSON.parse(fs16.readFileSync(manifestPath, "utf8"));
11913
+ manifest = JSON.parse(fs17.readFileSync(manifestPath, "utf8"));
11648
11914
  } catch (err) {
11649
11915
  return fail(invocation.format, `Could not read ${manifestPath}: ${err.message}`);
11650
11916
  }
@@ -11808,20 +12074,20 @@ function finishWatchRun(state, now) {
11808
12074
  };
11809
12075
  }
11810
12076
  function comparablePath(value) {
11811
- const absolute = path17.resolve(value);
12077
+ const absolute = path18.resolve(value);
11812
12078
  return process.platform === "win32" ? absolute.toLowerCase() : absolute;
11813
12079
  }
11814
12080
  function isSameOrInside(parent, candidate) {
11815
- const relative11 = path17.relative(parent, candidate);
11816
- return relative11 === "" || relative11 !== ".." && !relative11.startsWith(`..${path17.sep}`) && !path17.isAbsolute(relative11);
12081
+ const relative11 = path18.relative(parent, candidate);
12082
+ return relative11 === "" || relative11 !== ".." && !relative11.startsWith(`..${path18.sep}`) && !path18.isAbsolute(relative11);
11817
12083
  }
11818
12084
  function isGeneratedWatchPath(candidate, paths) {
11819
- const absolute = comparablePath(path17.resolve(paths.cwd, candidate));
11820
- const outDir = comparablePath(path17.resolve(paths.cwd, paths.outDir));
11821
- const tmpDir = comparablePath(path17.resolve(paths.cwd, paths.tmpDir));
12085
+ const absolute = comparablePath(path18.resolve(paths.cwd, candidate));
12086
+ const outDir = comparablePath(path18.resolve(paths.cwd, paths.outDir));
12087
+ const tmpDir = comparablePath(path18.resolve(paths.cwd, paths.tmpDir));
11822
12088
  if (isSameOrInside(outDir, absolute) || isSameOrInside(tmpDir, absolute)) return true;
11823
- const parent = path17.dirname(absolute);
11824
- if (parent === path17.dirname(outDir) && path17.basename(absolute).startsWith(`${path17.basename(outDir)}.backup-`)) {
12089
+ const parent = path18.dirname(absolute);
12090
+ if (parent === path18.dirname(outDir) && path18.basename(absolute).startsWith(`${path18.basename(outDir)}.backup-`)) {
11825
12091
  return true;
11826
12092
  }
11827
12093
  return absolute.split(/[\\/]+/).some((segment) => VCS_SEGMENTS.has(segment));
@@ -11838,8 +12104,8 @@ function decideWatchEvent(state, event, paths) {
11838
12104
  return { state, action: "schedule" };
11839
12105
  }
11840
12106
  async function runWatchLoop(invocation, resolved) {
11841
- const outDir = path17.resolve(resolved.cwd, resolved.outDir);
11842
- const tmpDir = path17.resolve(resolved.cwd, resolved.tmpDir);
12107
+ const outDir = path18.resolve(resolved.cwd, resolved.outDir);
12108
+ const tmpDir = path18.resolve(resolved.cwd, resolved.tmpDir);
11843
12109
  const paths = { cwd: resolved.cwd, outDir, tmpDir };
11844
12110
  let state = initialWatchState();
11845
12111
  let timer = null;
@@ -11904,11 +12170,11 @@ async function runWatchLoop(invocation, resolved) {
11904
12170
  };
11905
12171
  info("\u{1F440} Watching for changes. Press Ctrl+C to stop.");
11906
12172
  void regenerate();
11907
- const watcher = fs16.watch(resolved.cwd, { recursive: true }, (_event, filename) => {
12173
+ const watcher = fs17.watch(resolved.cwd, { recursive: true }, (_event, filename) => {
11908
12174
  const decision = decideWatchEvent(
11909
12175
  state,
11910
12176
  {
11911
- path: filename ? path17.resolve(resolved.cwd, filename.toString()) : null,
12177
+ path: filename ? path18.resolve(resolved.cwd, filename.toString()) : null,
11912
12178
  now: performance.now()
11913
12179
  },
11914
12180
  paths
@@ -11936,7 +12202,7 @@ async function runWatchLoop(invocation, resolved) {
11936
12202
  return 0;
11937
12203
  }
11938
12204
  var entryFile = process.argv[1] ?? "";
11939
- var entryName = path17.basename(entryFile).toLowerCase();
12205
+ var entryName = path18.basename(entryFile).toLowerCase();
11940
12206
  var invokedDirectly = entryName === "cli.js" || entryName === "cli.cjs";
11941
12207
  if (invokedDirectly) {
11942
12208
  void main().then(