@getcodesentinel/codesentinel 1.17.0 → 1.17.1

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/index.js CHANGED
@@ -7,6 +7,12 @@ import { Command, Option } from "commander";
7
7
  import { existsSync, readFileSync } from "fs";
8
8
  import { join } from "path";
9
9
  import { setTimeout as sleep } from "timers/promises";
10
+ import { join as join4 } from "path";
11
+ import { homedir } from "os";
12
+ import { join as join2 } from "path";
13
+ import { createHash } from "crypto";
14
+ import { mkdir, readdir, readFile, rename, stat, unlink, writeFile } from "fs/promises";
15
+ import { join as join3 } from "path";
10
16
  var round4 = (value) => Number(value.toFixed(4));
11
17
  var normalizeNodes = (nodes) => {
12
18
  const byName = /* @__PURE__ */ new Map();
@@ -614,6 +620,23 @@ var parseLockfileExtraction = (lockfileKind, lockfileRaw, directSpecs) => {
614
620
  throw new Error("unsupported_lockfile_format");
615
621
  }
616
622
  };
623
+ var cachedFetch = async (options) => {
624
+ const nowMs = options.nowMs ?? Date.now();
625
+ const cachedEntry = options.cacheStore === null ? null : await options.cacheStore.get(options.key);
626
+ if (cachedEntry !== null && nowMs - cachedEntry.fetchedAtMs <= options.ttlMs) {
627
+ return cachedEntry.value;
628
+ }
629
+ try {
630
+ const fresh = await options.fetchFresh();
631
+ if (fresh !== null) {
632
+ void options.cacheStore?.set(options.key, { value: fresh, fetchedAtMs: nowMs }).catch(() => {
633
+ });
634
+ return fresh;
635
+ }
636
+ } catch {
637
+ }
638
+ return cachedEntry?.value ?? null;
639
+ };
617
640
  var parseRetryAfterMs = (value) => {
618
641
  if (value === null) {
619
642
  return null;
@@ -640,8 +663,202 @@ var fetchJsonWithRetry = async (url, options) => {
640
663
  }
641
664
  return null;
642
665
  };
666
+ var resolveCodesentinelCacheDir = (env = process.env) => {
667
+ const explicit = env["CODESENTINEL_CACHE_DIR"]?.trim();
668
+ if (explicit !== void 0 && explicit.length > 0) {
669
+ return explicit;
670
+ }
671
+ if (process.platform === "win32") {
672
+ const localAppData = env["LOCALAPPDATA"]?.trim();
673
+ if (localAppData !== void 0 && localAppData.length > 0) {
674
+ return join2(localAppData, "codesentinel", "Cache");
675
+ }
676
+ return join2(homedir(), "AppData", "Local", "codesentinel", "Cache");
677
+ }
678
+ const xdgCacheHome = env["XDG_CACHE_HOME"]?.trim();
679
+ if (xdgCacheHome !== void 0 && xdgCacheHome.length > 0) {
680
+ return join2(xdgCacheHome, "codesentinel");
681
+ }
682
+ return join2(homedir(), ".cache", "codesentinel");
683
+ };
684
+ var parseCacheEntryPayload = (value) => {
685
+ if (typeof value !== "object" || value === null) {
686
+ return null;
687
+ }
688
+ const payload = value;
689
+ if (typeof payload.key !== "string" || payload.key.length === 0) {
690
+ return null;
691
+ }
692
+ if (typeof payload.fetchedAtMs !== "number" || !Number.isFinite(payload.fetchedAtMs)) {
693
+ return null;
694
+ }
695
+ return {
696
+ key: payload.key,
697
+ fetchedAtMs: payload.fetchedAtMs,
698
+ value: payload.value
699
+ };
700
+ };
701
+ var DEFAULT_OPTIONS = {
702
+ maxBytes: 100 * 1024 * 1024,
703
+ maxEntryBytes: 4 * 1024 * 1024,
704
+ sweepIntervalWrites: 25
705
+ };
706
+ var FileCacheStore = class {
707
+ constructor(directoryPath, options = DEFAULT_OPTIONS) {
708
+ this.directoryPath = directoryPath;
709
+ this.options = options;
710
+ }
711
+ byKey = /* @__PURE__ */ new Map();
712
+ inFlightWrites = /* @__PURE__ */ new Map();
713
+ writesSinceSweep = 0;
714
+ sweepPromise = Promise.resolve();
715
+ toEntryPath(key) {
716
+ const digest = createHash("sha256").update(key).digest("hex");
717
+ return join3(this.directoryPath, `${digest}.json`);
718
+ }
719
+ async writeEntry(key, entry) {
720
+ const filePath = this.toEntryPath(key);
721
+ await mkdir(this.directoryPath, { recursive: true });
722
+ const tempPath = `${filePath}.tmp`;
723
+ const payload = {
724
+ key,
725
+ fetchedAtMs: entry.fetchedAtMs,
726
+ value: entry.value
727
+ };
728
+ const raw = JSON.stringify(payload);
729
+ if (Buffer.byteLength(raw, "utf8") > this.options.maxEntryBytes) {
730
+ return;
731
+ }
732
+ await writeFile(tempPath, raw, "utf8");
733
+ await rename(tempPath, filePath);
734
+ }
735
+ async sweepIfNeeded() {
736
+ this.writesSinceSweep += 1;
737
+ if (this.writesSinceSweep < this.options.sweepIntervalWrites) {
738
+ return;
739
+ }
740
+ this.writesSinceSweep = 0;
741
+ this.sweepPromise = this.sweepPromise.catch(() => {
742
+ }).then(async () => {
743
+ await this.evictToSizeLimit();
744
+ });
745
+ await this.sweepPromise;
746
+ }
747
+ async evictToSizeLimit() {
748
+ let entries;
749
+ try {
750
+ const dirEntries = await readdir(this.directoryPath, { withFileTypes: true });
751
+ entries = (await Promise.all(
752
+ dirEntries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map(async (entry) => {
753
+ const path = join3(this.directoryPath, entry.name);
754
+ const info = await stat(path);
755
+ return { path, size: info.size, mtimeMs: info.mtimeMs };
756
+ })
757
+ )).filter((entry) => Number.isFinite(entry.size) && entry.size > 0);
758
+ } catch {
759
+ return;
760
+ }
761
+ let totalBytes = entries.reduce((sum, entry) => sum + entry.size, 0);
762
+ if (totalBytes <= this.options.maxBytes) {
763
+ return;
764
+ }
765
+ entries.sort((a, b) => a.mtimeMs - b.mtimeMs);
766
+ for (const entry of entries) {
767
+ if (totalBytes <= this.options.maxBytes) {
768
+ break;
769
+ }
770
+ try {
771
+ await unlink(entry.path);
772
+ totalBytes -= entry.size;
773
+ } catch {
774
+ }
775
+ }
776
+ }
777
+ async get(key) {
778
+ if (this.byKey.has(key)) {
779
+ return this.byKey.get(key) ?? null;
780
+ }
781
+ try {
782
+ const raw = await readFile(this.toEntryPath(key), "utf8");
783
+ const parsed = parseCacheEntryPayload(JSON.parse(raw));
784
+ if (parsed === null || parsed.key !== key) {
785
+ this.byKey.set(key, null);
786
+ return null;
787
+ }
788
+ const value = { fetchedAtMs: parsed.fetchedAtMs, value: parsed.value };
789
+ this.byKey.set(key, value);
790
+ return value;
791
+ } catch {
792
+ this.byKey.set(key, null);
793
+ return null;
794
+ }
795
+ }
796
+ async set(key, entry) {
797
+ const normalized = entry;
798
+ this.byKey.set(key, normalized);
799
+ const previous = this.inFlightWrites.get(key) ?? Promise.resolve();
800
+ const next = previous.catch(() => {
801
+ }).then(async () => {
802
+ await this.writeEntry(key, normalized);
803
+ await this.sweepIfNeeded();
804
+ });
805
+ this.inFlightWrites.set(key, next);
806
+ await next;
807
+ }
808
+ };
809
+ var SIX_HOURS_MS = 6 * 60 * 60 * 1e3;
810
+ var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
811
+ var DEFAULT_MAX_BYTES = 100 * 1024 * 1024;
812
+ var DEFAULT_MAX_ENTRY_BYTES = 4 * 1024 * 1024;
813
+ var DEFAULT_SWEEP_INTERVAL_WRITES = 25;
814
+ var cacheStoreSingleton;
815
+ var parsePositiveIntegerFromEnv = (value, fallback) => {
816
+ if (value === void 0) {
817
+ return fallback;
818
+ }
819
+ const parsed = Number.parseInt(value, 10);
820
+ if (!Number.isFinite(parsed) || parsed <= 0) {
821
+ return fallback;
822
+ }
823
+ return parsed;
824
+ };
825
+ var cacheDisabled = (env) => {
826
+ const mode = env["CODESENTINEL_CACHE_MODE"]?.trim().toLowerCase();
827
+ return mode === "none";
828
+ };
829
+ var getNpmMetadataCacheStore = () => {
830
+ if (cacheStoreSingleton !== void 0) {
831
+ return cacheStoreSingleton;
832
+ }
833
+ if (cacheDisabled(process.env)) {
834
+ cacheStoreSingleton = null;
835
+ return cacheStoreSingleton;
836
+ }
837
+ const path = join4(resolveCodesentinelCacheDir(process.env), "npm-metadata-v2");
838
+ cacheStoreSingleton = new FileCacheStore(path, {
839
+ maxBytes: parsePositiveIntegerFromEnv(
840
+ process.env["CODESENTINEL_CACHE_MAX_BYTES"],
841
+ DEFAULT_MAX_BYTES
842
+ ),
843
+ maxEntryBytes: parsePositiveIntegerFromEnv(
844
+ process.env["CODESENTINEL_CACHE_MAX_ENTRY_BYTES"],
845
+ DEFAULT_MAX_ENTRY_BYTES
846
+ ),
847
+ sweepIntervalWrites: parsePositiveIntegerFromEnv(
848
+ process.env["CODESENTINEL_CACHE_SWEEP_INTERVAL_WRITES"],
849
+ DEFAULT_SWEEP_INTERVAL_WRITES
850
+ )
851
+ });
852
+ return cacheStoreSingleton;
853
+ };
854
+ var getPackumentCacheTtlMs = () => parsePositiveIntegerFromEnv(process.env["CODESENTINEL_CACHE_TTL_PACKUMENT_MS"], SIX_HOURS_MS);
855
+ var getWeeklyDownloadsCacheTtlMs = () => parsePositiveIntegerFromEnv(process.env["CODESENTINEL_CACHE_TTL_DOWNLOADS_MS"], ONE_DAY_MS);
856
+ var toMetadataPackumentCacheKey = (name) => `npm:packument:metadata:${name}`;
857
+ var toGraphPackumentCacheKey = (name) => `npm:packument:graph:${name}`;
858
+ var toWeeklyDownloadsCacheKey = (name) => `npm:downloads:last-week:${name}`;
643
859
  var MAX_RETRIES = 3;
644
860
  var RETRY_BASE_DELAY_MS = 500;
861
+ var PACKUMENT_CACHE_STORE = getNpmMetadataCacheStore();
645
862
  var parsePrerelease = (value) => {
646
863
  if (value === void 0 || value.length === 0) {
647
864
  return [];
@@ -892,23 +1109,62 @@ var resolveRangeVersion = (versions, requested) => {
892
1109
  }
893
1110
  return null;
894
1111
  };
1112
+ var slimPackumentForGraph = (payload) => {
1113
+ const versions = payload.versions ?? {};
1114
+ const dependenciesByVersion = {};
1115
+ const versionNames = Object.keys(versions);
1116
+ for (const [version2, manifest] of Object.entries(versions)) {
1117
+ const dependenciesRaw = manifest?.dependencies ?? {};
1118
+ const dependencies = {};
1119
+ for (const [dependencyName, dependencyRange] of Object.entries(dependenciesRaw)) {
1120
+ if (dependencyName.length > 0 && dependencyRange.length > 0) {
1121
+ dependencies[dependencyName] = dependencyRange;
1122
+ }
1123
+ }
1124
+ if (Object.keys(dependencies).length > 0) {
1125
+ dependenciesByVersion[version2] = dependencies;
1126
+ }
1127
+ }
1128
+ const slim = {
1129
+ versionNames,
1130
+ dependenciesByVersion
1131
+ };
1132
+ if (payload["dist-tags"] !== void 0) {
1133
+ slim["dist-tags"] = payload["dist-tags"];
1134
+ }
1135
+ return slim;
1136
+ };
895
1137
  var fetchPackument = async (name) => {
896
1138
  const encodedName = encodeURIComponent(name);
897
1139
  try {
898
- return await fetchJsonWithRetry(`https://registry.npmjs.org/${encodedName}`, {
899
- retries: MAX_RETRIES,
900
- baseDelayMs: RETRY_BASE_DELAY_MS
1140
+ return await cachedFetch({
1141
+ key: toGraphPackumentCacheKey(name),
1142
+ ttlMs: getPackumentCacheTtlMs(),
1143
+ cacheStore: PACKUMENT_CACHE_STORE,
1144
+ fetchFresh: async () => {
1145
+ const payload = await fetchJsonWithRetry(
1146
+ `https://registry.npmjs.org/${encodedName}`,
1147
+ {
1148
+ retries: MAX_RETRIES,
1149
+ baseDelayMs: RETRY_BASE_DELAY_MS
1150
+ }
1151
+ );
1152
+ if (payload === null) {
1153
+ return null;
1154
+ }
1155
+ return slimPackumentForGraph(payload);
1156
+ }
901
1157
  });
902
1158
  } catch {
903
1159
  return null;
904
1160
  }
905
1161
  };
906
1162
  var resolveRequestedVersion = (packument, requested) => {
907
- const versions = packument.versions ?? {};
908
- const versionKeys = Object.keys(versions);
1163
+ const versionKeys = [...packument.versionNames];
1164
+ const versionSet = new Set(versionKeys);
909
1165
  const tags = packument["dist-tags"] ?? {};
910
1166
  const latest = tags["latest"];
911
- if (requested !== null && versions[requested] !== void 0) {
1167
+ if (requested !== null && versionSet.has(requested)) {
912
1168
  return {
913
1169
  version: requested,
914
1170
  resolution: "exact",
@@ -917,7 +1173,7 @@ var resolveRequestedVersion = (packument, requested) => {
917
1173
  }
918
1174
  if (requested !== null) {
919
1175
  const tagged = tags[requested];
920
- if (tagged !== void 0 && versions[tagged] !== void 0) {
1176
+ if (tagged !== void 0 && versionSet.has(tagged)) {
921
1177
  return {
922
1178
  version: tagged,
923
1179
  resolution: "tag",
@@ -927,7 +1183,7 @@ var resolveRequestedVersion = (packument, requested) => {
927
1183
  }
928
1184
  if (requested !== null) {
929
1185
  const matched = resolveRangeVersion(versionKeys, requested);
930
- if (matched !== null && versions[matched] !== void 0) {
1186
+ if (matched !== null && versionSet.has(matched)) {
931
1187
  return {
932
1188
  version: matched,
933
1189
  resolution: "range",
@@ -935,7 +1191,7 @@ var resolveRequestedVersion = (packument, requested) => {
935
1191
  };
936
1192
  }
937
1193
  }
938
- if (latest !== void 0 && versions[latest] !== void 0) {
1194
+ if (latest !== void 0 && versionSet.has(latest)) {
939
1195
  return {
940
1196
  version: latest,
941
1197
  resolution: "latest",
@@ -1016,8 +1272,8 @@ var resolveRegistryGraphFromDirectSpecs = async (directSpecs, options) => {
1016
1272
  if (nodesByKey.has(nodeKey)) {
1017
1273
  continue;
1018
1274
  }
1019
- const manifest = (packument.versions ?? {})[resolved.version] ?? {};
1020
- const dependencies = Object.entries(manifest.dependencies ?? {}).filter(
1275
+ const manifestDependencies = packument.dependenciesByVersion[resolved.version] ?? {};
1276
+ const dependencies = Object.entries(manifestDependencies).filter(
1021
1277
  ([dependencyName, dependencyRange]) => dependencyName.length > 0 && dependencyRange.length > 0
1022
1278
  ).sort((a, b) => a[0].localeCompare(b[0]));
1023
1279
  nodesByKey.set(nodeKey, {
@@ -1301,7 +1557,7 @@ var analyzeDependencyCandidate = async (input, metadataProvider) => {
1301
1557
  external
1302
1558
  };
1303
1559
  };
1304
- var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
1560
+ var ONE_DAY_MS2 = 24 * 60 * 60 * 1e3;
1305
1561
  var MAX_RETRIES2 = 3;
1306
1562
  var RETRY_BASE_DELAY_MS2 = 500;
1307
1563
  var round42 = (value) => Number(value.toFixed(4));
@@ -1314,12 +1570,18 @@ var parseDate = (iso) => {
1314
1570
  };
1315
1571
  var NpmRegistryMetadataProvider = class {
1316
1572
  cache = /* @__PURE__ */ new Map();
1573
+ cacheStore = getNpmMetadataCacheStore();
1317
1574
  async fetchWeeklyDownloads(name) {
1318
1575
  const encodedName = encodeURIComponent(name);
1319
- const payload = await fetchJsonWithRetry(
1320
- `https://api.npmjs.org/downloads/point/last-week/${encodedName}`,
1321
- { retries: MAX_RETRIES2, baseDelayMs: RETRY_BASE_DELAY_MS2 }
1322
- );
1576
+ const payload = await cachedFetch({
1577
+ key: toWeeklyDownloadsCacheKey(name),
1578
+ ttlMs: getWeeklyDownloadsCacheTtlMs(),
1579
+ cacheStore: this.cacheStore,
1580
+ fetchFresh: async () => await fetchJsonWithRetry(
1581
+ `https://api.npmjs.org/downloads/point/last-week/${encodedName}`,
1582
+ { retries: MAX_RETRIES2, baseDelayMs: RETRY_BASE_DELAY_MS2 }
1583
+ )
1584
+ });
1323
1585
  if (payload === null) {
1324
1586
  return null;
1325
1587
  }
@@ -1336,10 +1598,31 @@ var NpmRegistryMetadataProvider = class {
1336
1598
  }
1337
1599
  try {
1338
1600
  const encodedName = encodeURIComponent(name);
1339
- const payload = await fetchJsonWithRetry(
1340
- `https://registry.npmjs.org/${encodedName}`,
1341
- { retries: MAX_RETRIES2, baseDelayMs: RETRY_BASE_DELAY_MS2 }
1342
- );
1601
+ const payload = await cachedFetch({
1602
+ key: toMetadataPackumentCacheKey(name),
1603
+ ttlMs: getPackumentCacheTtlMs(),
1604
+ cacheStore: this.cacheStore,
1605
+ fetchFresh: async () => {
1606
+ const fresh = await fetchJsonWithRetry(
1607
+ `https://registry.npmjs.org/${encodedName}`,
1608
+ {
1609
+ retries: MAX_RETRIES2,
1610
+ baseDelayMs: RETRY_BASE_DELAY_MS2
1611
+ }
1612
+ );
1613
+ if (fresh === null) {
1614
+ return null;
1615
+ }
1616
+ const slim = {};
1617
+ if (fresh.time !== void 0) {
1618
+ slim.time = fresh.time;
1619
+ }
1620
+ if (fresh.maintainers !== void 0) {
1621
+ slim.maintainers = fresh.maintainers;
1622
+ }
1623
+ return slim;
1624
+ }
1625
+ });
1343
1626
  if (payload === null) {
1344
1627
  this.cache.set(key, null);
1345
1628
  return null;
@@ -1348,7 +1631,7 @@ var NpmRegistryMetadataProvider = class {
1348
1631
  const publishDates = Object.entries(timeEntries).filter(([tag]) => tag !== "created" && tag !== "modified").map(([, date]) => parseDate(date)).filter((value) => value !== null).sort((a, b) => a - b);
1349
1632
  const modifiedAt = parseDate(timeEntries["modified"]);
1350
1633
  const now = Date.now();
1351
- const daysSinceLastRelease = modifiedAt === null ? null : Math.max(0, round42((now - modifiedAt) / ONE_DAY_MS));
1634
+ const daysSinceLastRelease = modifiedAt === null ? null : Math.max(0, round42((now - modifiedAt) / ONE_DAY_MS2));
1352
1635
  let releaseFrequencyDays = null;
1353
1636
  if (publishDates.length >= 2) {
1354
1637
  const totalIntervals = publishDates.length - 1;
@@ -1360,7 +1643,7 @@ var NpmRegistryMetadataProvider = class {
1360
1643
  sum += current - previous;
1361
1644
  }
1362
1645
  }
1363
- releaseFrequencyDays = round42(sum / totalIntervals / ONE_DAY_MS);
1646
+ releaseFrequencyDays = round42(sum / totalIntervals / ONE_DAY_MS2);
1364
1647
  }
1365
1648
  const maintainers = payload.maintainers ?? [];
1366
1649
  const maintainerCount = maintainers.length > 0 ? maintainers.length : null;
@@ -1925,7 +2208,7 @@ var formatReport = (report, format) => {
1925
2208
 
1926
2209
  // ../governance/dist/index.js
1927
2210
  import { mkdirSync, rmSync } from "fs";
1928
- import { basename, join as join2, resolve } from "path";
2211
+ import { basename, join as join5, resolve } from "path";
1929
2212
  import { execFile } from "child_process";
1930
2213
  import { promisify } from "util";
1931
2214
  var EXIT_CODES = {
@@ -2446,7 +2729,7 @@ var tryRunGit = async (repositoryPath, args) => {
2446
2729
  }
2447
2730
  };
2448
2731
  var buildWorktreePath = (repoRoot, sha) => {
2449
- const tmpRoot = join2(repoRoot, SENTINEL_TMP_DIR, WORKTREE_DIR);
2732
+ const tmpRoot = join5(repoRoot, SENTINEL_TMP_DIR, WORKTREE_DIR);
2450
2733
  mkdirSync(tmpRoot, { recursive: true });
2451
2734
  const baseName = `baseline-${sha.slice(0, 12)}-${process.pid}`;
2452
2735
  const candidate = resolve(tmpRoot, baseName);
@@ -2538,7 +2821,7 @@ var resolveAutoBaselineRef = async (input) => {
2538
2821
 
2539
2822
  // src/index.ts
2540
2823
  import { readFileSync as readFileSync2 } from "fs";
2541
- import { readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
2824
+ import { readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
2542
2825
  import { dirname as dirname2, resolve as resolve5 } from "path";
2543
2826
  import { fileURLToPath } from "url";
2544
2827
 
@@ -2931,13 +3214,13 @@ var parseLogLevel = (value) => {
2931
3214
 
2932
3215
  // src/application/check-for-updates.ts
2933
3216
  import { spawn } from "child_process";
2934
- import { mkdir, readFile, writeFile } from "fs/promises";
2935
- import { homedir } from "os";
2936
- import { dirname, join as join3 } from "path";
3217
+ import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
3218
+ import { homedir as homedir2 } from "os";
3219
+ import { dirname, join as join6 } from "path";
2937
3220
  import { stderr, stdin } from "process";
2938
3221
  import { clearScreenDown, cursorTo, emitKeypressEvents } from "readline";
2939
3222
  var UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
2940
- var UPDATE_CACHE_PATH = join3(homedir(), ".cache", "codesentinel", "update-check.json");
3223
+ var UPDATE_CACHE_PATH = join6(homedir2(), ".cache", "codesentinel", "update-check.json");
2941
3224
  var SEMVER_PATTERN = /^(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(?:-(?<prerelease>[0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
2942
3225
  var ANSI = {
2943
3226
  reset: "\x1B[0m",
@@ -3061,7 +3344,7 @@ var parseNpmViewVersionOutput = (output) => {
3061
3344
  };
3062
3345
  var readCache = async () => {
3063
3346
  try {
3064
- const raw = await readFile(UPDATE_CACHE_PATH, "utf8");
3347
+ const raw = await readFile2(UPDATE_CACHE_PATH, "utf8");
3065
3348
  const parsed = JSON.parse(raw);
3066
3349
  if (typeof parsed === "object" && parsed !== null && typeof parsed.lastCheckedAt === "string") {
3067
3350
  return { lastCheckedAt: parsed.lastCheckedAt };
@@ -3072,8 +3355,8 @@ var readCache = async () => {
3072
3355
  return null;
3073
3356
  };
3074
3357
  var writeCache = async (cache) => {
3075
- await mkdir(dirname(UPDATE_CACHE_PATH), { recursive: true });
3076
- await writeFile(UPDATE_CACHE_PATH, JSON.stringify(cache), "utf8");
3358
+ await mkdir2(dirname(UPDATE_CACHE_PATH), { recursive: true });
3359
+ await writeFile2(UPDATE_CACHE_PATH, JSON.stringify(cache), "utf8");
3077
3360
  };
3078
3361
  var shouldRunUpdateCheck = (input) => {
3079
3362
  if (!input.isInteractive) {
@@ -6590,7 +6873,7 @@ var runAnalyzeCommand = async (inputPath, authorIdentityMode, options = {}, logg
6590
6873
  };
6591
6874
 
6592
6875
  // src/application/run-check-command.ts
6593
- import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
6876
+ import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
6594
6877
 
6595
6878
  // src/application/build-analysis-snapshot.ts
6596
6879
  var buildAnalysisSnapshot = async (inputPath, authorIdentityMode, options, logger) => {
@@ -6674,7 +6957,7 @@ var runCheckCommand = async (inputPath, authorIdentityMode, options, logger = cr
6674
6957
  let diff;
6675
6958
  if (options.baselinePath !== void 0) {
6676
6959
  logger.info(`loading baseline snapshot: ${options.baselinePath}`);
6677
- const baselineRaw = await readFile2(options.baselinePath, "utf8");
6960
+ const baselineRaw = await readFile3(options.baselinePath, "utf8");
6678
6961
  try {
6679
6962
  baseline = parseSnapshot(baselineRaw);
6680
6963
  } catch (error) {
@@ -6700,7 +6983,7 @@ var runCheckCommand = async (inputPath, authorIdentityMode, options, logger = cr
6700
6983
  options.outputFormat
6701
6984
  );
6702
6985
  if (options.outputPath !== void 0) {
6703
- await writeFile2(options.outputPath, rendered, "utf8");
6986
+ await writeFile3(options.outputPath, rendered, "utf8");
6704
6987
  logger.info(`check output written: ${options.outputPath}`);
6705
6988
  }
6706
6989
  return {
@@ -6713,7 +6996,7 @@ var runCheckCommand = async (inputPath, authorIdentityMode, options, logger = cr
6713
6996
  };
6714
6997
 
6715
6998
  // src/application/run-ci-command.ts
6716
- import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
6999
+ import { readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
6717
7000
  import { relative as relative2, resolve as resolve4 } from "path";
6718
7001
  var isPathOutsideBase = (value) => {
6719
7002
  return value === ".." || value.startsWith("../") || value.startsWith("..\\");
@@ -6740,7 +7023,7 @@ var runCiCommand = async (inputPath, authorIdentityMode, options, logger = creat
6740
7023
  logger
6741
7024
  );
6742
7025
  if (options.snapshotPath !== void 0) {
6743
- await writeFile3(options.snapshotPath, JSON.stringify(current, null, 2), "utf8");
7026
+ await writeFile4(options.snapshotPath, JSON.stringify(current, null, 2), "utf8");
6744
7027
  logger.info(`snapshot written: ${options.snapshotPath}`);
6745
7028
  }
6746
7029
  let baseline;
@@ -6813,7 +7096,7 @@ var runCiCommand = async (inputPath, authorIdentityMode, options, logger = creat
6813
7096
  diff = compareSnapshots(current, baseline);
6814
7097
  } else if (options.baselinePath !== void 0) {
6815
7098
  logger.info(`loading baseline snapshot: ${options.baselinePath}`);
6816
- const baselineRaw = await readFile3(options.baselinePath, "utf8");
7099
+ const baselineRaw = await readFile4(options.baselinePath, "utf8");
6817
7100
  try {
6818
7101
  baseline = parseSnapshot(baselineRaw);
6819
7102
  } catch (error) {
@@ -6835,7 +7118,7 @@ var runCiCommand = async (inputPath, authorIdentityMode, options, logger = creat
6835
7118
 
6836
7119
  ${ciMarkdown}`;
6837
7120
  if (options.reportPath !== void 0) {
6838
- await writeFile3(options.reportPath, markdownSummary, "utf8");
7121
+ await writeFile4(options.reportPath, markdownSummary, "utf8");
6839
7122
  logger.info(`report written: ${options.reportPath}`);
6840
7123
  }
6841
7124
  const machineReadable = {
@@ -6847,7 +7130,7 @@ ${ciMarkdown}`;
6847
7130
  exitCode: gateResult.exitCode
6848
7131
  };
6849
7132
  if (options.jsonOutputPath !== void 0) {
6850
- await writeFile3(options.jsonOutputPath, JSON.stringify(machineReadable, null, 2), "utf8");
7133
+ await writeFile4(options.jsonOutputPath, JSON.stringify(machineReadable, null, 2), "utf8");
6851
7134
  logger.info(`ci machine output written: ${options.jsonOutputPath}`);
6852
7135
  }
6853
7136
  return {
@@ -6861,7 +7144,7 @@ ${ciMarkdown}`;
6861
7144
  };
6862
7145
 
6863
7146
  // src/application/run-report-command.ts
6864
- import { readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
7147
+ import { readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
6865
7148
  var runReportCommand = async (inputPath, authorIdentityMode, options, logger = createSilentLogger()) => {
6866
7149
  logger.info("building analysis snapshot");
6867
7150
  const current = await buildAnalysisSnapshot(
@@ -6875,7 +7158,7 @@ var runReportCommand = async (inputPath, authorIdentityMode, options, logger = c
6875
7158
  logger
6876
7159
  );
6877
7160
  if (options.snapshotPath !== void 0) {
6878
- await writeFile4(options.snapshotPath, JSON.stringify(current, null, 2), "utf8");
7161
+ await writeFile5(options.snapshotPath, JSON.stringify(current, null, 2), "utf8");
6879
7162
  logger.info(`snapshot written: ${options.snapshotPath}`);
6880
7163
  }
6881
7164
  let report;
@@ -6883,14 +7166,14 @@ var runReportCommand = async (inputPath, authorIdentityMode, options, logger = c
6883
7166
  report = createReport(current);
6884
7167
  } else {
6885
7168
  logger.info(`loading baseline snapshot: ${options.comparePath}`);
6886
- const baselineRaw = await readFile4(options.comparePath, "utf8");
7169
+ const baselineRaw = await readFile5(options.comparePath, "utf8");
6887
7170
  const baseline = parseSnapshot(baselineRaw);
6888
7171
  const diff = compareSnapshots(current, baseline);
6889
7172
  report = createReport(current, diff);
6890
7173
  }
6891
7174
  const rendered = formatReport(report, options.format);
6892
7175
  if (options.outputPath !== void 0) {
6893
- await writeFile4(options.outputPath, rendered, "utf8");
7176
+ await writeFile5(options.outputPath, rendered, "utf8");
6894
7177
  logger.info(`report written: ${options.outputPath}`);
6895
7178
  }
6896
7179
  return { report, rendered };
@@ -7269,12 +7552,12 @@ program.command("run").argument("[path]", "path to the project to analyze").addO
7269
7552
  ...options.trace === true ? { trace: explain.trace } : {}
7270
7553
  });
7271
7554
  if (options.snapshot !== void 0) {
7272
- await writeFile5(options.snapshot, JSON.stringify(snapshot, null, 2), "utf8");
7555
+ await writeFile6(options.snapshot, JSON.stringify(snapshot, null, 2), "utf8");
7273
7556
  logger.info(`snapshot written: ${options.snapshot}`);
7274
7557
  }
7275
7558
  const report = options.compare === void 0 ? createReport(snapshot) : createReport(
7276
7559
  snapshot,
7277
- compareSnapshots(snapshot, parseSnapshot(await readFile5(options.compare, "utf8")))
7560
+ compareSnapshots(snapshot, parseSnapshot(await readFile6(options.compare, "utf8")))
7278
7561
  );
7279
7562
  if (options.format === "json") {
7280
7563
  const analyzeSummaryOutput = formatAnalyzeOutput(explain.summary, "summary");