@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 +329 -46
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
899
|
-
|
|
900
|
-
|
|
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
|
|
908
|
-
const
|
|
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 &&
|
|
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 &&
|
|
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 &&
|
|
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 &&
|
|
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
|
|
1020
|
-
const dependencies = Object.entries(
|
|
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
|
|
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
|
|
1320
|
-
|
|
1321
|
-
|
|
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
|
|
1340
|
-
|
|
1341
|
-
|
|
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) /
|
|
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 /
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
3076
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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");
|