@ankurhalder/codebase-snapshot 4.0.0 → 4.0.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/bin.js +453 -284
- package/dist/{chunk-FM4OOQPF.js → chunk-RGIMMEAW.js} +293 -123
- package/dist/cli.cjs +417 -248
- package/dist/cli.d.cts +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +4 -5
- package/dist/index.cjs +291 -121
- package/dist/index.d.cts +14 -9
- package/dist/index.d.ts +14 -9
- package/dist/index.js +1 -1
- package/dist/{types-BdpT_4b8.d.cts → types-LSfwsKE-.d.cts} +1 -0
- package/dist/{types-BdpT_4b8.d.ts → types-LSfwsKE-.d.ts} +1 -0
- package/docs/cli.md +5 -3
- package/docs/troubleshooting.md +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2218,11 +2218,19 @@ function isSensitivePath(relativePath) {
|
|
|
2218
2218
|
}
|
|
2219
2219
|
return matchesSensitiveList(posixPath, base);
|
|
2220
2220
|
}
|
|
2221
|
-
|
|
2221
|
+
var activeSecretRules = null;
|
|
2222
|
+
function setActiveSecretRules(rules) {
|
|
2223
|
+
activeSecretRules = rules === null ? null : [...rules];
|
|
2224
|
+
}
|
|
2225
|
+
function pathScanRules(extraRules) {
|
|
2226
|
+
const fallback = extraRules ?? activeSecretRules ?? [];
|
|
2227
|
+
return [...DEFAULT_SECRET_PATTERNS, ...fallback];
|
|
2228
|
+
}
|
|
2229
|
+
function findSecretInPath(relativePath, extraRules) {
|
|
2222
2230
|
const posixPath = relativePath.replace(/\\/g, "/");
|
|
2223
2231
|
const spans = [];
|
|
2224
2232
|
const rules = [];
|
|
2225
|
-
for (const { rule, pattern } of
|
|
2233
|
+
for (const { rule, pattern } of pathScanRules(extraRules)) {
|
|
2226
2234
|
const scan = new RegExp(pattern.source, `${pattern.flags.replace(/[gy]/g, "")}g`);
|
|
2227
2235
|
let match;
|
|
2228
2236
|
while ((match = scan.exec(posixPath)) !== null) {
|
|
@@ -2230,24 +2238,34 @@ function findSecretInPath(relativePath) {
|
|
|
2230
2238
|
scan.lastIndex += 1;
|
|
2231
2239
|
continue;
|
|
2232
2240
|
}
|
|
2233
|
-
spans.push({ start: match.index, end: match.index + match[0].length
|
|
2241
|
+
spans.push({ start: match.index, end: match.index + match[0].length });
|
|
2234
2242
|
if (!rules.includes(rule)) rules.push(rule);
|
|
2235
2243
|
}
|
|
2236
2244
|
}
|
|
2237
2245
|
if (spans.length === 0) return null;
|
|
2238
2246
|
spans.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
2247
|
+
const merged = [];
|
|
2248
|
+
for (const span of spans) {
|
|
2249
|
+
const last = merged[merged.length - 1];
|
|
2250
|
+
if (last && span.start <= last.end) last.end = Math.max(last.end, span.end);
|
|
2251
|
+
else merged.push({ start: span.start, end: span.end });
|
|
2252
|
+
}
|
|
2239
2253
|
let out = "";
|
|
2240
2254
|
let cursor = 0;
|
|
2241
|
-
for (const span of
|
|
2242
|
-
|
|
2243
|
-
const start = Math.max(span.start, cursor);
|
|
2244
|
-
out += posixPath.slice(cursor, start);
|
|
2255
|
+
for (const span of merged) {
|
|
2256
|
+
out += posixPath.slice(cursor, span.start);
|
|
2245
2257
|
out += REDACTION_MARKER;
|
|
2246
|
-
cursor =
|
|
2258
|
+
cursor = span.end;
|
|
2247
2259
|
}
|
|
2248
2260
|
out += posixPath.slice(cursor);
|
|
2249
2261
|
return { rules, masked: out };
|
|
2250
2262
|
}
|
|
2263
|
+
function maskSkipPaths(records, extraRules) {
|
|
2264
|
+
return records.map((record) => {
|
|
2265
|
+
const hit = findSecretInPath(record.path, extraRules);
|
|
2266
|
+
return hit ? { ...record, path: hit.masked } : record;
|
|
2267
|
+
});
|
|
2268
|
+
}
|
|
2251
2269
|
function globToRegExp(glob) {
|
|
2252
2270
|
const normalized = glob.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+$/, "");
|
|
2253
2271
|
const anchored = normalized.startsWith("/");
|
|
@@ -2478,6 +2496,7 @@ function collectFiles(cwd, options = {}) {
|
|
|
2478
2496
|
const includePatterns = options.includePatterns ?? [];
|
|
2479
2497
|
const excludePatterns = options.excludePatterns ?? [];
|
|
2480
2498
|
const includeSensitiveFiles = options.includeSensitiveFiles ?? false;
|
|
2499
|
+
const pathRules = options.secretRules;
|
|
2481
2500
|
const isToolOwned = makeToolOwnedDecider(cwd);
|
|
2482
2501
|
let candidates;
|
|
2483
2502
|
const skipped = [];
|
|
@@ -2513,7 +2532,7 @@ function collectFiles(cwd, options = {}) {
|
|
|
2513
2532
|
}
|
|
2514
2533
|
}
|
|
2515
2534
|
} catch {
|
|
2516
|
-
const walked = walkDirectory(cwd, cwd, /* @__PURE__ */ new Set(), true);
|
|
2535
|
+
const walked = walkDirectory(cwd, cwd, rootRealFor(cwd), /* @__PURE__ */ new Set(), true);
|
|
2517
2536
|
candidates = walked.files;
|
|
2518
2537
|
skipped.push(...walked.skipped);
|
|
2519
2538
|
}
|
|
@@ -2551,7 +2570,7 @@ function collectFiles(cwd, options = {}) {
|
|
|
2551
2570
|
});
|
|
2552
2571
|
return false;
|
|
2553
2572
|
}
|
|
2554
|
-
const secret = findSecretInPath(file);
|
|
2573
|
+
const secret = findSecretInPath(file, pathRules);
|
|
2555
2574
|
if (secret) {
|
|
2556
2575
|
skipped.push({
|
|
2557
2576
|
path: secret.masked,
|
|
@@ -2562,30 +2581,29 @@ function collectFiles(cwd, options = {}) {
|
|
|
2562
2581
|
}
|
|
2563
2582
|
return true;
|
|
2564
2583
|
}).sort();
|
|
2565
|
-
return { files, skipped };
|
|
2584
|
+
return { files, skipped: maskSkipPaths(skipped, pathRules) };
|
|
2566
2585
|
}
|
|
2567
|
-
function
|
|
2568
|
-
const results = { files: [], skipped: [] };
|
|
2569
|
-
let realDir;
|
|
2570
|
-
try {
|
|
2571
|
-
realDir = fs9__namespace.realpathSync(dir);
|
|
2572
|
-
} catch {
|
|
2573
|
-
realDir = dir;
|
|
2574
|
-
}
|
|
2575
|
-
if (visited.has(realDir)) return results;
|
|
2576
|
-
visited.add(realDir);
|
|
2577
|
-
let rootReal;
|
|
2586
|
+
function rootRealFor(root) {
|
|
2578
2587
|
try {
|
|
2579
|
-
|
|
2588
|
+
return fs9__namespace.realpathSync(root);
|
|
2580
2589
|
} catch {
|
|
2581
|
-
|
|
2590
|
+
return root;
|
|
2582
2591
|
}
|
|
2592
|
+
}
|
|
2593
|
+
function walkDirectory(dir, baseDir, rootReal, visited, isRoot = false) {
|
|
2594
|
+
const results = { files: [], skipped: [] };
|
|
2595
|
+
if (visited.has(dir)) return results;
|
|
2596
|
+
visited.add(dir);
|
|
2583
2597
|
const ignoredByGitignore = isRoot ? readGitignoreMatcher(baseDir) : () => false;
|
|
2584
2598
|
let entries;
|
|
2585
2599
|
try {
|
|
2586
2600
|
entries = fs9__namespace.readdirSync(dir, { withFileTypes: true });
|
|
2587
2601
|
} catch {
|
|
2588
|
-
results.skipped.push({
|
|
2602
|
+
results.skipped.push({
|
|
2603
|
+
path: path10__namespace.relative(baseDir, dir).replace(/\\/g, "/") || ".",
|
|
2604
|
+
reason: "read-error",
|
|
2605
|
+
detail: "directory unreadable"
|
|
2606
|
+
});
|
|
2589
2607
|
return results;
|
|
2590
2608
|
}
|
|
2591
2609
|
for (const entry of entries) {
|
|
@@ -2664,7 +2682,7 @@ function walkDirectory(dir, baseDir, visited, isRoot = false) {
|
|
|
2664
2682
|
isFile = true;
|
|
2665
2683
|
}
|
|
2666
2684
|
if (isDirectory) {
|
|
2667
|
-
const nested = walkDirectory(fullPath, baseDir, visited);
|
|
2685
|
+
const nested = walkDirectory(fullPath, baseDir, rootReal, visited);
|
|
2668
2686
|
results.files.push(...nested.files);
|
|
2669
2687
|
results.skipped.push(...nested.skipped);
|
|
2670
2688
|
} else if (isFile) {
|
|
@@ -3256,6 +3274,7 @@ function resolveConfig(userConfig, cliOptions, baseDir) {
|
|
|
3256
3274
|
...aliasedRules ?? []
|
|
3257
3275
|
]);
|
|
3258
3276
|
const secretRules = disableDefaultPatterns ? compiledCustomRules : [...compileSecretRules(DEFAULT_SECRET_PATTERNS), ...compiledCustomRules];
|
|
3277
|
+
setActiveSecretRules(secretRules);
|
|
3259
3278
|
const cliMonolith = cliOptions?.includeMonolith;
|
|
3260
3279
|
const includeMonolith = cliMonolith ?? strictBoolean(userConfig?.includeMonolith, false, "`includeMonolith`");
|
|
3261
3280
|
const artifacts = resolveArtifacts(
|
|
@@ -3363,7 +3382,8 @@ function defineConfig(config) {
|
|
|
3363
3382
|
}
|
|
3364
3383
|
|
|
3365
3384
|
// src/generator/audit.ts
|
|
3366
|
-
function generateAuditReport(manifest, secretFindings) {
|
|
3385
|
+
function generateAuditReport(manifest, secretFindings, secretRules) {
|
|
3386
|
+
const mask = (value) => findSecretInPath(value, secretRules)?.masked ?? value;
|
|
3367
3387
|
const lines = [
|
|
3368
3388
|
"# Codebase Health & Security Audit",
|
|
3369
3389
|
"",
|
|
@@ -3398,7 +3418,7 @@ function generateAuditReport(manifest, secretFindings) {
|
|
|
3398
3418
|
"| :--- | :--- | :--- |"
|
|
3399
3419
|
);
|
|
3400
3420
|
for (const finding of secretFindings) {
|
|
3401
|
-
lines.push(`| \`${finding.path ?? "unknown"}\` | ${finding.line} | \`${finding.rule}\` |`);
|
|
3421
|
+
lines.push(`| \`${mask(finding.path ?? "unknown")}\` | ${finding.line} | \`${finding.rule}\` |`);
|
|
3402
3422
|
}
|
|
3403
3423
|
lines.push("", "### Matches by rule", "", "| Rule | Matches |", "| :--- | :--- |");
|
|
3404
3424
|
for (const [rule, count] of Array.from(byRule.entries()).sort((a, b) => b[1] - a[1])) {
|
|
@@ -3420,7 +3440,7 @@ function generateAuditReport(manifest, secretFindings) {
|
|
|
3420
3440
|
for (const file of largeFiles) {
|
|
3421
3441
|
const sizeKb = (file.sizeBytes / 1024).toFixed(1);
|
|
3422
3442
|
const status = file.isPreviewTruncated ? "Truncated Head/Tail" : "Full";
|
|
3423
|
-
lines.push(`| \`${file.relativePath}\` | ${sizeKb} KB | ${file.lines} | ${status} |`);
|
|
3443
|
+
lines.push(`| \`${mask(file.relativePath)}\` | ${sizeKb} KB | ${file.lines} | ${status} |`);
|
|
3424
3444
|
}
|
|
3425
3445
|
lines.push("");
|
|
3426
3446
|
}
|
|
@@ -3462,7 +3482,7 @@ function generateAuditReport(manifest, secretFindings) {
|
|
|
3462
3482
|
"| :--- | :--- | :--- |"
|
|
3463
3483
|
);
|
|
3464
3484
|
for (const skip of manifest.skipped) {
|
|
3465
|
-
lines.push(`| \`${skip.path}\` | \`${skip.reason}\` | ${skip.detail ?? "-"} |`);
|
|
3485
|
+
lines.push(`| \`${mask(skip.path)}\` | \`${skip.reason}\` | ${skip.detail ?? "-"} |`);
|
|
3466
3486
|
}
|
|
3467
3487
|
lines.push("");
|
|
3468
3488
|
}
|
|
@@ -4124,6 +4144,9 @@ function detectLanguage(filePath) {
|
|
|
4124
4144
|
const ext = path10__namespace.posix.extname(base).toLowerCase();
|
|
4125
4145
|
return LANGUAGE_BY_EXTENSION[ext] ?? "text";
|
|
4126
4146
|
}
|
|
4147
|
+
function maskedPath(value, secretRules) {
|
|
4148
|
+
return findSecretInPath(value, secretRules)?.masked ?? value;
|
|
4149
|
+
}
|
|
4127
4150
|
function emptyDrift() {
|
|
4128
4151
|
return {
|
|
4129
4152
|
missingInSnapshot: [],
|
|
@@ -4194,15 +4217,20 @@ function validateSnapshot(configInput) {
|
|
|
4194
4217
|
const skippedSet = new Set(
|
|
4195
4218
|
manifest.skipped.filter((entry) => entry && typeof entry.path === "string").map((entry) => entry.path)
|
|
4196
4219
|
);
|
|
4220
|
+
const isSkippedOnDisk = (diskFile) => {
|
|
4221
|
+
if (skippedSet.has(diskFile)) return true;
|
|
4222
|
+
return skippedSet.has(maskedPath(diskFile, config.secretRules));
|
|
4223
|
+
};
|
|
4197
4224
|
const collection = collectFiles(config.cwd, {
|
|
4198
4225
|
includePatterns: config.include,
|
|
4199
4226
|
excludePatterns: [...config.excludePatterns, ...config.presetExclude],
|
|
4200
|
-
includeSensitiveFiles: config.includeSensitiveFiles
|
|
4227
|
+
includeSensitiveFiles: config.includeSensitiveFiles,
|
|
4228
|
+
secretRules: config.secretRules
|
|
4201
4229
|
});
|
|
4202
4230
|
for (const diskFile of collection.files) {
|
|
4203
4231
|
const snapshotHash = manifestFileMap.get(diskFile);
|
|
4204
4232
|
if (!snapshotHash) {
|
|
4205
|
-
if (
|
|
4233
|
+
if (isSkippedOnDisk(diskFile) && !wouldNowBeIncluded(config.cwd, diskFile)) continue;
|
|
4206
4234
|
drift.missingInSnapshot.push(diskFile);
|
|
4207
4235
|
continue;
|
|
4208
4236
|
}
|
|
@@ -4471,10 +4499,19 @@ function validateSnapshot(configInput) {
|
|
|
4471
4499
|
`${drift.configMismatches.length} configuration mismatch(es) between the manifest and this run.`
|
|
4472
4500
|
);
|
|
4473
4501
|
}
|
|
4502
|
+
const maskedDrift = {
|
|
4503
|
+
...drift,
|
|
4504
|
+
missingInSnapshot: drift.missingInSnapshot.map((value) => maskedPath(value, config.secretRules)),
|
|
4505
|
+
missingOnDisk: drift.missingOnDisk.map((value) => maskedPath(value, config.secretRules)),
|
|
4506
|
+
hashMismatches: drift.hashMismatches.map((mismatch) => ({
|
|
4507
|
+
...mismatch,
|
|
4508
|
+
path: maskedPath(mismatch.path, config.secretRules)
|
|
4509
|
+
}))
|
|
4510
|
+
};
|
|
4474
4511
|
return {
|
|
4475
4512
|
valid: errors.length === 0,
|
|
4476
4513
|
manifestPresent: true,
|
|
4477
|
-
drift,
|
|
4514
|
+
drift: maskedDrift,
|
|
4478
4515
|
errors,
|
|
4479
4516
|
warnings
|
|
4480
4517
|
};
|
|
@@ -4509,18 +4546,22 @@ function readManifest2(config) {
|
|
|
4509
4546
|
function explainPath(config, target) {
|
|
4510
4547
|
const relative4 = normalizeTarget(config.cwd, target);
|
|
4511
4548
|
const absolute = path10__namespace.join(config.cwd, relative4);
|
|
4549
|
+
const maskedPath2 = findSecretInPath(relative4, config.secretRules)?.masked ?? relative4;
|
|
4512
4550
|
const result = {
|
|
4513
|
-
path:
|
|
4551
|
+
path: maskedPath2,
|
|
4514
4552
|
exists: fs9__namespace.existsSync(absolute),
|
|
4515
4553
|
included: false
|
|
4516
4554
|
};
|
|
4517
4555
|
const collection = collectFiles(config.cwd, {
|
|
4518
4556
|
includePatterns: config.include,
|
|
4519
4557
|
excludePatterns: [...config.excludePatterns, ...config.presetExclude],
|
|
4520
|
-
includeSensitiveFiles: config.includeSensitiveFiles
|
|
4558
|
+
includeSensitiveFiles: config.includeSensitiveFiles,
|
|
4559
|
+
secretRules: config.secretRules
|
|
4521
4560
|
});
|
|
4522
4561
|
if (!collection.files.includes(relative4)) {
|
|
4523
|
-
const record = collection.skipped.find(
|
|
4562
|
+
const record = collection.skipped.find(
|
|
4563
|
+
(entry2) => entry2.path === relative4 || entry2.path === maskedPath2
|
|
4564
|
+
);
|
|
4524
4565
|
if (record) {
|
|
4525
4566
|
result.reason = record.reason;
|
|
4526
4567
|
result.detail = record.detail;
|
|
@@ -4557,7 +4598,7 @@ function explainPath(config, target) {
|
|
|
4557
4598
|
result.secrets = findings.slice(0, 20).map((finding) => ({ rule: finding.rule, line: finding.line }));
|
|
4558
4599
|
}
|
|
4559
4600
|
const manifest = readManifest2(config);
|
|
4560
|
-
const entry = manifest?.files.find((file) => file.relativePath === relative4);
|
|
4601
|
+
const entry = Array.isArray(manifest?.files) ? manifest.files.find((file) => file.relativePath === relative4) : void 0;
|
|
4561
4602
|
result.part = entry?.part ?? null;
|
|
4562
4603
|
result.inclusionMode = entry?.inclusionMode;
|
|
4563
4604
|
return result;
|
|
@@ -4662,12 +4703,13 @@ function compareManifests(before, after) {
|
|
|
4662
4703
|
if (!right.has(filePath)) removed.push(filePath);
|
|
4663
4704
|
}
|
|
4664
4705
|
const sort = (values) => values.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
4706
|
+
const mask = (values) => values.map((value) => findSecretInPath(value)?.masked ?? value);
|
|
4665
4707
|
return {
|
|
4666
4708
|
before: side(before),
|
|
4667
4709
|
after: side(after),
|
|
4668
|
-
added: sort(added),
|
|
4669
|
-
removed: sort(removed),
|
|
4670
|
-
changed: sort(changed),
|
|
4710
|
+
added: mask(sort(added)),
|
|
4711
|
+
removed: mask(sort(removed)),
|
|
4712
|
+
changed: mask(sort(changed)),
|
|
4671
4713
|
unchanged
|
|
4672
4714
|
};
|
|
4673
4715
|
}
|
|
@@ -5392,7 +5434,7 @@ async function runInit(options) {
|
|
|
5392
5434
|
|
|
5393
5435
|
// src/index.ts
|
|
5394
5436
|
var GENERATOR_NAME = "@ankurhalder/codebase-snapshot";
|
|
5395
|
-
var GENERATOR_VERSION = "4.0.
|
|
5437
|
+
var GENERATOR_VERSION = "4.0.1";
|
|
5396
5438
|
var SCHEMA_VERSION = "3.0.0";
|
|
5397
5439
|
function sha256Hex2(input) {
|
|
5398
5440
|
return crypto__namespace.createHash("sha256").update(input).digest("hex");
|
|
@@ -5429,7 +5471,6 @@ function bump(counts, key) {
|
|
|
5429
5471
|
}
|
|
5430
5472
|
var RELATIVE_SPECIFIER = /^\.{1,2}\//;
|
|
5431
5473
|
var IMPORT_CANDIDATE_SUFFIXES = [
|
|
5432
|
-
"",
|
|
5433
5474
|
".ts",
|
|
5434
5475
|
".tsx",
|
|
5435
5476
|
".mts",
|
|
@@ -5443,23 +5484,59 @@ var IMPORT_CANDIDATE_SUFFIXES = [
|
|
|
5443
5484
|
"/index.js",
|
|
5444
5485
|
"/index.mjs"
|
|
5445
5486
|
];
|
|
5446
|
-
|
|
5487
|
+
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
5488
|
+
".ts",
|
|
5489
|
+
".tsx",
|
|
5490
|
+
".mts",
|
|
5491
|
+
".cts",
|
|
5492
|
+
".js",
|
|
5493
|
+
".jsx",
|
|
5494
|
+
".mjs",
|
|
5495
|
+
".cjs"
|
|
5496
|
+
]);
|
|
5497
|
+
function buildImportResolver(files) {
|
|
5498
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
5499
|
+
const byPathFolded = /* @__PURE__ */ new Map();
|
|
5500
|
+
const byStem = /* @__PURE__ */ new Map();
|
|
5501
|
+
const byStemFolded = /* @__PURE__ */ new Map();
|
|
5502
|
+
const remember = (map, key, value) => {
|
|
5503
|
+
if (!map.has(key)) map.set(key, value);
|
|
5504
|
+
};
|
|
5505
|
+
for (const file of files) {
|
|
5506
|
+
const relativePath = file.relativePath;
|
|
5507
|
+
remember(byPath, relativePath, relativePath);
|
|
5508
|
+
remember(byPathFolded, relativePath.toLowerCase(), relativePath);
|
|
5509
|
+
const extension = path10__namespace.posix.extname(relativePath);
|
|
5510
|
+
if (!SOURCE_EXTENSIONS.has(extension)) continue;
|
|
5511
|
+
const stem = relativePath.slice(0, -extension.length);
|
|
5512
|
+
remember(byStem, stem, relativePath);
|
|
5513
|
+
remember(byStemFolded, stem.toLowerCase(), relativePath);
|
|
5514
|
+
if (path10__namespace.posix.basename(stem) === "index") {
|
|
5515
|
+
const directory = path10__namespace.posix.dirname(stem);
|
|
5516
|
+
remember(byStem, directory, relativePath);
|
|
5517
|
+
remember(byStemFolded, directory.toLowerCase(), relativePath);
|
|
5518
|
+
}
|
|
5519
|
+
}
|
|
5520
|
+
return { byPath, byPathFolded, byStem, byStemFolded };
|
|
5521
|
+
}
|
|
5522
|
+
function resolveSpecifier(fromFile, specifier, resolver) {
|
|
5447
5523
|
if (!RELATIVE_SPECIFIER.test(specifier)) return null;
|
|
5448
|
-
const
|
|
5449
|
-
|
|
5450
|
-
|
|
5524
|
+
const joined = path10__namespace.posix.normalize(
|
|
5525
|
+
path10__namespace.posix.join(path10__namespace.posix.dirname(fromFile), specifier)
|
|
5526
|
+
);
|
|
5527
|
+
const exact = (key) => resolver.byPath.get(key) ?? resolver.byPathFolded.get(key.toLowerCase()) ?? null;
|
|
5528
|
+
const direct = exact(joined);
|
|
5529
|
+
if (direct) return direct;
|
|
5451
5530
|
for (const suffix of IMPORT_CANDIDATE_SUFFIXES) {
|
|
5452
|
-
const
|
|
5453
|
-
if (
|
|
5454
|
-
}
|
|
5455
|
-
const extensionSwap = new RegExp(`${candidate}\\.(?:ts|tsx|mts|cts|js|jsx|mjs|cjs)$`);
|
|
5456
|
-
for (const file of knownFiles) {
|
|
5457
|
-
if (extensionSwap.test(file)) return file;
|
|
5531
|
+
const hit = exact(`${joined}${suffix}`);
|
|
5532
|
+
if (hit) return hit;
|
|
5458
5533
|
}
|
|
5459
|
-
|
|
5534
|
+
const stem = joined.replace(/\.(?:js|mjs|cjs|jsx)$/, "");
|
|
5535
|
+
const byStem = (key) => resolver.byStem.get(key) ?? resolver.byStemFolded.get(key.toLowerCase()) ?? null;
|
|
5536
|
+
return byStem(joined) ?? byStem(stem);
|
|
5460
5537
|
}
|
|
5461
5538
|
function buildIndexes(files) {
|
|
5462
|
-
const
|
|
5539
|
+
const resolver = buildImportResolver(files);
|
|
5463
5540
|
const importerCounts = /* @__PURE__ */ new Map();
|
|
5464
5541
|
const byFile = files.filter((file) => isSourceSummary(file.summary)).map((file) => {
|
|
5465
5542
|
const summary = file.summary;
|
|
@@ -5471,7 +5548,7 @@ function buildIndexes(files) {
|
|
|
5471
5548
|
});
|
|
5472
5549
|
for (const entry of byFile) {
|
|
5473
5550
|
for (const specifier of entry.imports) {
|
|
5474
|
-
const resolved = resolveSpecifier(entry.path, specifier,
|
|
5551
|
+
const resolved = resolveSpecifier(entry.path, specifier, resolver);
|
|
5475
5552
|
if (resolved) importerCounts.set(resolved, (importerCounts.get(resolved) ?? 0) + 1);
|
|
5476
5553
|
}
|
|
5477
5554
|
}
|
|
@@ -5562,15 +5639,22 @@ function resolveSafeOutputDirs(config) {
|
|
|
5562
5639
|
return { outDir, tmpDir };
|
|
5563
5640
|
}
|
|
5564
5641
|
var PLACEHOLDER_ENTRIES = /* @__PURE__ */ new Set([".gitkeep", ".gitignore", ".DS_Store"]);
|
|
5565
|
-
var
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5642
|
+
var RUN_DIR_PREFIX = "run-";
|
|
5643
|
+
var STALE_RUN_MS = 60 * 60 * 1e3;
|
|
5644
|
+
function maskPathText(value, secretRules) {
|
|
5645
|
+
return findSecretInPath(value, secretRules)?.masked ?? value;
|
|
5646
|
+
}
|
|
5647
|
+
function maskSkipRecords(records, secretRules) {
|
|
5648
|
+
return maskSkipPaths(records, secretRules);
|
|
5649
|
+
}
|
|
5650
|
+
function isProcessAlive(pid) {
|
|
5651
|
+
try {
|
|
5652
|
+
process.kill(pid, 0);
|
|
5653
|
+
return true;
|
|
5654
|
+
} catch (err) {
|
|
5655
|
+
return err.code !== "ESRCH";
|
|
5656
|
+
}
|
|
5657
|
+
}
|
|
5574
5658
|
var OWNERSHIP_MARKER = ".codebase-snapshot";
|
|
5575
5659
|
var SUPPORTED_MARKER_SCHEMAS = /* @__PURE__ */ new Set([SCHEMA_VERSION]);
|
|
5576
5660
|
var SNAPSHOT_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -5600,6 +5684,7 @@ function markerPayload(dir, state, id, createdAt) {
|
|
|
5600
5684
|
createdAt,
|
|
5601
5685
|
state,
|
|
5602
5686
|
id,
|
|
5687
|
+
pid: process.pid,
|
|
5603
5688
|
entries: listEntries(dir)
|
|
5604
5689
|
};
|
|
5605
5690
|
const manifestPath = path10__namespace.join(dir, "manifest.json");
|
|
@@ -5663,6 +5748,7 @@ function readOwnershipMarker(dir) {
|
|
|
5663
5748
|
createdAt: typeof candidate.createdAt === "string" ? candidate.createdAt : "unknown",
|
|
5664
5749
|
state: candidate.state,
|
|
5665
5750
|
id: candidate.id,
|
|
5751
|
+
pid: typeof candidate.pid === "number" ? candidate.pid : void 0,
|
|
5666
5752
|
manifestSha256: typeof candidate.manifestSha256 === "string" ? candidate.manifestSha256 : void 0,
|
|
5667
5753
|
entries: Array.isArray(candidate.entries) && candidate.entries.every((entry) => typeof entry === "string") ? candidate.entries : void 0
|
|
5668
5754
|
},
|
|
@@ -5770,7 +5856,7 @@ function describeEntries(entries, limit = 5) {
|
|
|
5770
5856
|
const shown = entries.slice(0, limit).join(", ");
|
|
5771
5857
|
return entries.length > limit ? `${shown}, and ${entries.length - limit} more` : shown;
|
|
5772
5858
|
}
|
|
5773
|
-
function assertReplaceable(target, label) {
|
|
5859
|
+
function assertReplaceable(target, label, secretRules) {
|
|
5774
5860
|
if (!fs9__namespace.existsSync(target)) return;
|
|
5775
5861
|
if (!fs9__namespace.statSync(target).isDirectory()) {
|
|
5776
5862
|
throw new Error(
|
|
@@ -5779,34 +5865,89 @@ function assertReplaceable(target, label) {
|
|
|
5779
5865
|
}
|
|
5780
5866
|
const entries = fs9__namespace.readdirSync(target);
|
|
5781
5867
|
if (entries.length === 0) return;
|
|
5782
|
-
if (
|
|
5783
|
-
const {
|
|
5784
|
-
if (label === "tmpDir") {
|
|
5785
|
-
if (!marker2) {
|
|
5786
|
-
throw new Error(
|
|
5787
|
-
`Refusing to replace tmpDir ${target}: ${problem ?? "it does not carry this generator's marker"}. This generator only clears a staging directory it wrote. Point tmpDir at a new or empty directory, or remove ${target} yourself.`
|
|
5788
|
-
);
|
|
5789
|
-
}
|
|
5790
|
-
const unexpected = entries.filter((name) => !STAGING_ENTRIES.has(name));
|
|
5791
|
-
if (unexpected.length > 0) {
|
|
5792
|
-
throw new Error(
|
|
5793
|
-
`Refusing to replace tmpDir ${target}: it holds ${describeEntries(unexpected)}, which this generator did not write. Point tmpDir at a new or empty directory, or remove those files yourself.`
|
|
5794
|
-
);
|
|
5795
|
-
}
|
|
5796
|
-
return;
|
|
5797
|
-
}
|
|
5868
|
+
if (entries.every((name) => PLACEHOLDER_ENTRIES.has(name))) return;
|
|
5869
|
+
const { problem } = readOwnershipMarker(target);
|
|
5798
5870
|
const verdict = assessSnapshotDirectory(target);
|
|
5799
5871
|
if (verdict.owned) return;
|
|
5872
|
+
const shownForeign = verdict.foreignEntries.map((name) => maskPathText(name, secretRules));
|
|
5873
|
+
const shownEntries = entries.map((name) => maskPathText(name, secretRules));
|
|
5800
5874
|
if (verdict.foreignEntries.length > 0) {
|
|
5801
5875
|
throw new Error(
|
|
5802
|
-
`Refusing to replace ${label} ${target}: it carries this generator's ownership marker, but these entries are not part of the snapshot it recorded: ${describeEntries(
|
|
5876
|
+
`Refusing to replace ${label} ${target}: it carries this generator's ownership marker, but these entries are not part of the snapshot it recorded: ${describeEntries(shownForeign)}. Remove them yourself, or point ${label} at a new or empty directory.`
|
|
5803
5877
|
);
|
|
5804
5878
|
}
|
|
5805
5879
|
const reason = verdict.problem ?? problem ?? "it does not look like a snapshot this generator wrote";
|
|
5806
5880
|
throw new Error(
|
|
5807
|
-
`Refusing to replace ${label} ${target}: ${reason} (found ${describeEntries(
|
|
5881
|
+
`Refusing to replace ${label} ${target}: ${reason} (found ${describeEntries(shownEntries)}). Remove the directory yourself, or point ${label} at a new or empty directory.`
|
|
5808
5882
|
);
|
|
5809
5883
|
}
|
|
5884
|
+
function assertStagingRootUsable(tmpDir, secretRules) {
|
|
5885
|
+
if (!fs9__namespace.existsSync(tmpDir)) return;
|
|
5886
|
+
if (!fs9__namespace.statSync(tmpDir).isDirectory()) {
|
|
5887
|
+
throw new Error(`Refusing to write into tmpDir ${tmpDir}: it exists but is not a directory.`);
|
|
5888
|
+
}
|
|
5889
|
+
const entries = fs9__namespace.readdirSync(tmpDir);
|
|
5890
|
+
if (entries.length === 0) return;
|
|
5891
|
+
const foreign = entries.filter((name) => {
|
|
5892
|
+
const full = path10__namespace.join(tmpDir, name);
|
|
5893
|
+
if (!name.startsWith(RUN_DIR_PREFIX)) return true;
|
|
5894
|
+
let stats;
|
|
5895
|
+
try {
|
|
5896
|
+
stats = fs9__namespace.statSync(full);
|
|
5897
|
+
} catch {
|
|
5898
|
+
return true;
|
|
5899
|
+
}
|
|
5900
|
+
if (!stats.isDirectory()) return true;
|
|
5901
|
+
const { marker: marker2 } = readOwnershipMarker(full);
|
|
5902
|
+
if (marker2) return false;
|
|
5903
|
+
try {
|
|
5904
|
+
return fs9__namespace.readdirSync(full).length > 0;
|
|
5905
|
+
} catch {
|
|
5906
|
+
return true;
|
|
5907
|
+
}
|
|
5908
|
+
});
|
|
5909
|
+
if (foreign.length > 0) {
|
|
5910
|
+
const shown = describeEntries(foreign.map((name) => maskPathText(name, secretRules)));
|
|
5911
|
+
throw new Error(
|
|
5912
|
+
`Refusing to replace tmpDir ${tmpDir}: it holds ${shown}, which this generator did not write. Point tmpDir at a new or empty directory, or remove those files yourself.`
|
|
5913
|
+
);
|
|
5914
|
+
}
|
|
5915
|
+
}
|
|
5916
|
+
function cleanStaleRunDirs(tmpDir) {
|
|
5917
|
+
let entries;
|
|
5918
|
+
try {
|
|
5919
|
+
entries = fs9__namespace.readdirSync(tmpDir);
|
|
5920
|
+
} catch {
|
|
5921
|
+
return;
|
|
5922
|
+
}
|
|
5923
|
+
for (const name of entries) {
|
|
5924
|
+
if (!name.startsWith(RUN_DIR_PREFIX)) continue;
|
|
5925
|
+
const full = path10__namespace.join(tmpDir, name);
|
|
5926
|
+
const { marker: marker2 } = readOwnershipMarker(full);
|
|
5927
|
+
if (marker2) {
|
|
5928
|
+
const created = Date.parse(marker2.createdAt);
|
|
5929
|
+
const aged = !Number.isFinite(created) || Date.now() - created > STALE_RUN_MS;
|
|
5930
|
+
const abandoned = typeof marker2.pid === "number" && !isProcessAlive(marker2.pid);
|
|
5931
|
+
if (aged || abandoned) {
|
|
5932
|
+
try {
|
|
5933
|
+
fs9__namespace.rmSync(full, { recursive: true, force: true });
|
|
5934
|
+
} catch {
|
|
5935
|
+
}
|
|
5936
|
+
}
|
|
5937
|
+
continue;
|
|
5938
|
+
}
|
|
5939
|
+
try {
|
|
5940
|
+
if (fs9__namespace.readdirSync(full).length === 0) fs9__namespace.rmSync(full, { recursive: true, force: true });
|
|
5941
|
+
} catch {
|
|
5942
|
+
}
|
|
5943
|
+
}
|
|
5944
|
+
}
|
|
5945
|
+
function removeIfEmpty(dir) {
|
|
5946
|
+
try {
|
|
5947
|
+
if (fs9__namespace.readdirSync(dir).length === 0) fs9__namespace.rmSync(dir, { recursive: true, force: true });
|
|
5948
|
+
} catch {
|
|
5949
|
+
}
|
|
5950
|
+
}
|
|
5810
5951
|
function ensureParentDirectory(target, label) {
|
|
5811
5952
|
const parent = path10__namespace.dirname(target);
|
|
5812
5953
|
if (fs9__namespace.existsSync(parent) && !fs9__namespace.statSync(parent).isDirectory()) {
|
|
@@ -5822,14 +5963,12 @@ function ensureParentDirectory(target, label) {
|
|
|
5822
5963
|
);
|
|
5823
5964
|
}
|
|
5824
5965
|
}
|
|
5825
|
-
function acquireRunLock(
|
|
5826
|
-
const
|
|
5827
|
-
|
|
5828
|
-
`codebase-snapshot-${sha256Hex2(outDir).slice(0, 16)}.lock`
|
|
5829
|
-
);
|
|
5966
|
+
function acquireRunLock(stagingRoot) {
|
|
5967
|
+
const key = lockKeyFor(stagingRoot);
|
|
5968
|
+
const lockPath = path10__namespace.join(os__namespace.tmpdir(), `codebase-snapshot-${key}.lock`);
|
|
5830
5969
|
const payload = `${JSON.stringify({
|
|
5831
5970
|
pid: process.pid,
|
|
5832
|
-
|
|
5971
|
+
stagingRoot,
|
|
5833
5972
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5834
5973
|
})}
|
|
5835
5974
|
`;
|
|
@@ -5854,11 +5993,20 @@ function acquireRunLock(outDir) {
|
|
|
5854
5993
|
continue;
|
|
5855
5994
|
}
|
|
5856
5995
|
throw new Error(
|
|
5857
|
-
`Another generate run is already
|
|
5996
|
+
`Another generate run is already using the staging directory ${stagingRoot}. Wait for it to finish, or delete ${lockPath} if no other run is active.`
|
|
5858
5997
|
);
|
|
5859
5998
|
}
|
|
5860
5999
|
}
|
|
5861
|
-
throw new Error(`Could not acquire the generate lock for ${
|
|
6000
|
+
throw new Error(`Could not acquire the generate lock for ${stagingRoot}.`);
|
|
6001
|
+
}
|
|
6002
|
+
function lockKeyFor(stagingRoot) {
|
|
6003
|
+
let key = stagingRoot;
|
|
6004
|
+
try {
|
|
6005
|
+
key = fs9__namespace.realpathSync(stagingRoot);
|
|
6006
|
+
} catch {
|
|
6007
|
+
}
|
|
6008
|
+
if (process.platform === "win32" || process.platform === "darwin") key = key.toLowerCase();
|
|
6009
|
+
return sha256Hex2(key).slice(0, 16);
|
|
5862
6010
|
}
|
|
5863
6011
|
function lockOwnerIsGone(lockPath) {
|
|
5864
6012
|
let raw;
|
|
@@ -5894,18 +6042,32 @@ function writeManifestAtomically(manifestPath, manifest) {
|
|
|
5894
6042
|
throw err;
|
|
5895
6043
|
}
|
|
5896
6044
|
}
|
|
5897
|
-
function swapIntoPlace(
|
|
6045
|
+
function swapIntoPlace(stagingDir, outDir) {
|
|
5898
6046
|
ensureParentDirectory(outDir, "outDir");
|
|
6047
|
+
const deadline = Date.now() + 3e3;
|
|
6048
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
6049
|
+
try {
|
|
6050
|
+
swapOnce(stagingDir, outDir);
|
|
6051
|
+
return;
|
|
6052
|
+
} catch (err) {
|
|
6053
|
+
const code = err.code;
|
|
6054
|
+
const racy = code === "ENOENT" || code === "ENOTEMPTY" || code === "EEXIST" || code === "EPERM";
|
|
6055
|
+
if (!racy || attempt >= 10 || Date.now() > deadline) throw err;
|
|
6056
|
+
sleepSync(50);
|
|
6057
|
+
}
|
|
6058
|
+
}
|
|
6059
|
+
}
|
|
6060
|
+
function swapOnce(stagingDir, outDir) {
|
|
5899
6061
|
const backupDir = `${outDir}.backup-${process.pid}-${Date.now()}`;
|
|
5900
6062
|
const hadPrevious = fs9__namespace.existsSync(outDir);
|
|
5901
6063
|
if (hadPrevious) fs9__namespace.renameSync(outDir, backupDir);
|
|
5902
6064
|
try {
|
|
5903
6065
|
try {
|
|
5904
|
-
fs9__namespace.renameSync(
|
|
6066
|
+
fs9__namespace.renameSync(stagingDir, outDir);
|
|
5905
6067
|
} catch (err) {
|
|
5906
6068
|
if (err.code === "EXDEV") {
|
|
5907
|
-
fs9__namespace.cpSync(
|
|
5908
|
-
fs9__namespace.rmSync(
|
|
6069
|
+
fs9__namespace.cpSync(stagingDir, outDir, { recursive: true });
|
|
6070
|
+
fs9__namespace.rmSync(stagingDir, { recursive: true, force: true });
|
|
5909
6071
|
} else {
|
|
5910
6072
|
throw err;
|
|
5911
6073
|
}
|
|
@@ -5919,6 +6081,10 @@ function swapIntoPlace(tmpDir, outDir) {
|
|
|
5919
6081
|
throw err;
|
|
5920
6082
|
}
|
|
5921
6083
|
}
|
|
6084
|
+
function sleepSync(milliseconds) {
|
|
6085
|
+
const buffer = new Int32Array(new SharedArrayBuffer(4));
|
|
6086
|
+
Atomics.wait(buffer, 0, 0, milliseconds);
|
|
6087
|
+
}
|
|
5922
6088
|
function artifactWarnings(artifacts) {
|
|
5923
6089
|
const messages = [];
|
|
5924
6090
|
if (!artifacts.manifest) {
|
|
@@ -5981,11 +6147,12 @@ function generateSnapshot(configInput, options) {
|
|
|
5981
6147
|
const collection = collectFiles(config.cwd, {
|
|
5982
6148
|
includePatterns: config.include,
|
|
5983
6149
|
excludePatterns: [...config.excludePatterns, ...config.presetExclude],
|
|
5984
|
-
includeSensitiveFiles: config.includeSensitiveFiles
|
|
6150
|
+
includeSensitiveFiles: config.includeSensitiveFiles,
|
|
6151
|
+
secretRules: config.secretRules
|
|
5985
6152
|
});
|
|
5986
6153
|
const files = [];
|
|
5987
6154
|
const monolithBodies = /* @__PURE__ */ new Map();
|
|
5988
|
-
const skipped = [...collection.skipped];
|
|
6155
|
+
const skipped = maskSkipRecords([...collection.skipped], config.secretRules);
|
|
5989
6156
|
const secretFindings = [];
|
|
5990
6157
|
const warnings = [];
|
|
5991
6158
|
const layerCounts = {};
|
|
@@ -6059,12 +6226,12 @@ function generateSnapshot(configInput, options) {
|
|
|
6059
6226
|
summaryQuality = outcome?.quality;
|
|
6060
6227
|
if (isSourceSummary(summary) && summary.parseErrors) {
|
|
6061
6228
|
warnings.push(
|
|
6062
|
-
`Parse errors in ${relativePath} (${summary.parseErrors}); its summary is incomplete.`
|
|
6229
|
+
`Parse errors in ${maskPathText(relativePath, config.secretRules)} (${summary.parseErrors}); its summary is incomplete.`
|
|
6063
6230
|
);
|
|
6064
6231
|
}
|
|
6065
6232
|
} catch (err) {
|
|
6066
6233
|
warnings.push(
|
|
6067
|
-
`Summary skipped for ${relativePath}: ${err.message}`.replace(/\s+/g, " ")
|
|
6234
|
+
`Summary skipped for ${maskPathText(relativePath, config.secretRules)}: ${err.message}`.replace(/\s+/g, " ")
|
|
6068
6235
|
);
|
|
6069
6236
|
}
|
|
6070
6237
|
files.push({
|
|
@@ -6173,12 +6340,12 @@ function generateSnapshot(configInput, options) {
|
|
|
6173
6340
|
const { content: _content, ...rest } = file;
|
|
6174
6341
|
return rest;
|
|
6175
6342
|
}),
|
|
6176
|
-
skipped,
|
|
6343
|
+
skipped: maskSkipRecords(skipped, config.secretRules),
|
|
6177
6344
|
warnings
|
|
6178
6345
|
};
|
|
6179
6346
|
manifest.warnings = [
|
|
6180
6347
|
...warnings,
|
|
6181
|
-
...secretFindings.map((finding) => `${finding.rule} at ${finding.path ?? "unknown"}:${finding.line}`)
|
|
6348
|
+
...secretFindings.map((finding) => `${finding.rule} at ${maskPathText(finding.path ?? "unknown", config.secretRules)}:${finding.line}`)
|
|
6182
6349
|
];
|
|
6183
6350
|
manifest.totals.warningCount = manifest.warnings.length;
|
|
6184
6351
|
let monolithJson = null;
|
|
@@ -6224,31 +6391,33 @@ function generateSnapshot(configInput, options) {
|
|
|
6224
6391
|
manifest.totals.warningCount = manifest.warnings.length;
|
|
6225
6392
|
const { outDir, tmpDir } = resolveSafeOutputDirs(config);
|
|
6226
6393
|
const { artifacts } = config;
|
|
6227
|
-
assertReplaceable(
|
|
6228
|
-
|
|
6394
|
+
assertReplaceable(outDir, "outDir", config.secretRules);
|
|
6395
|
+
assertStagingRootUsable(tmpDir, config.secretRules);
|
|
6229
6396
|
if (dryRun) {
|
|
6230
6397
|
runAfterGenerate(config, manifest);
|
|
6231
6398
|
return manifest;
|
|
6232
6399
|
}
|
|
6233
|
-
const releaseLock = acquireRunLock(
|
|
6234
|
-
let
|
|
6400
|
+
const releaseLock = acquireRunLock(tmpDir);
|
|
6401
|
+
let stagingDir = null;
|
|
6235
6402
|
try {
|
|
6236
6403
|
ensureParentDirectory(outDir, "outDir");
|
|
6237
|
-
fs9__namespace.rmSync(tmpDir, { recursive: true, force: true });
|
|
6238
6404
|
fs9__namespace.mkdirSync(tmpDir, { recursive: true });
|
|
6239
|
-
|
|
6405
|
+
cleanStaleRunDirs(tmpDir);
|
|
6240
6406
|
const snapshotId = crypto__namespace.randomUUID();
|
|
6241
6407
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6242
|
-
|
|
6408
|
+
stagingDir = path10__namespace.join(tmpDir, `${RUN_DIR_PREFIX}${process.pid}-${snapshotId.slice(0, 8)}`);
|
|
6409
|
+
fs9__namespace.mkdirSync(stagingDir);
|
|
6410
|
+
writeOwnershipMarker(stagingDir, {
|
|
6243
6411
|
generator: GENERATOR_NAME,
|
|
6244
6412
|
version: GENERATOR_VERSION,
|
|
6245
6413
|
schemaVersion: SCHEMA_VERSION,
|
|
6246
6414
|
createdAt,
|
|
6247
6415
|
state: "staging",
|
|
6248
|
-
id: snapshotId
|
|
6416
|
+
id: snapshotId,
|
|
6417
|
+
pid: process.pid
|
|
6249
6418
|
});
|
|
6250
|
-
const partsDir = path10__namespace.join(
|
|
6251
|
-
const reportsDir = path10__namespace.join(
|
|
6419
|
+
const partsDir = path10__namespace.join(stagingDir, "parts");
|
|
6420
|
+
const reportsDir = path10__namespace.join(stagingDir, "reports");
|
|
6252
6421
|
if (artifacts.parts) fs9__namespace.mkdirSync(partsDir, { recursive: true });
|
|
6253
6422
|
if (artifacts.navigation || artifacts.projectTree || artifacts.audit) {
|
|
6254
6423
|
fs9__namespace.mkdirSync(reportsDir, { recursive: true });
|
|
@@ -6268,25 +6437,25 @@ function generateSnapshot(configInput, options) {
|
|
|
6268
6437
|
if (artifacts.audit) {
|
|
6269
6438
|
fs9__namespace.writeFileSync(
|
|
6270
6439
|
path10__namespace.join(reportsDir, "audit.md"),
|
|
6271
|
-
generateAuditReport(manifest, secretFindings),
|
|
6440
|
+
generateAuditReport(manifest, secretFindings, config.secretRules),
|
|
6272
6441
|
"utf8"
|
|
6273
6442
|
);
|
|
6274
6443
|
}
|
|
6275
6444
|
if (artifacts.readme) {
|
|
6276
|
-
fs9__namespace.writeFileSync(path10__namespace.join(
|
|
6445
|
+
fs9__namespace.writeFileSync(path10__namespace.join(stagingDir, "README.md"), generateReadme(manifest), "utf8");
|
|
6277
6446
|
}
|
|
6278
6447
|
if (artifacts.manifest) {
|
|
6279
|
-
fs9__namespace.writeFileSync(path10__namespace.join(
|
|
6448
|
+
fs9__namespace.writeFileSync(path10__namespace.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
|
|
6280
6449
|
}
|
|
6281
6450
|
if (monolithJson !== null) {
|
|
6282
|
-
fs9__namespace.writeFileSync(path10__namespace.join(
|
|
6451
|
+
fs9__namespace.writeFileSync(path10__namespace.join(stagingDir, "full-codebase.json"), monolithJson, "utf8");
|
|
6283
6452
|
}
|
|
6284
6453
|
if (monolithMarkdown !== null) {
|
|
6285
|
-
fs9__namespace.writeFileSync(path10__namespace.join(
|
|
6454
|
+
fs9__namespace.writeFileSync(path10__namespace.join(stagingDir, "full-codebase.md"), monolithMarkdown, "utf8");
|
|
6286
6455
|
}
|
|
6287
|
-
writeOwnershipMarker(
|
|
6288
|
-
swapIntoPlace(
|
|
6289
|
-
|
|
6456
|
+
writeOwnershipMarker(stagingDir, markerPayload(stagingDir, "complete", snapshotId, createdAt));
|
|
6457
|
+
swapIntoPlace(stagingDir, outDir);
|
|
6458
|
+
stagingDir = null;
|
|
6290
6459
|
const warningsBeforeHook = manifest.warnings.length;
|
|
6291
6460
|
runAfterGenerate(config, manifest);
|
|
6292
6461
|
if (artifacts.manifest && manifest.warnings.length !== warningsBeforeHook) {
|
|
@@ -6295,14 +6464,15 @@ function generateSnapshot(configInput, options) {
|
|
|
6295
6464
|
writeOwnershipMarker(outDir, markerPayload(outDir, "complete", snapshotId, createdAt));
|
|
6296
6465
|
return manifest;
|
|
6297
6466
|
} catch (err) {
|
|
6298
|
-
if (
|
|
6467
|
+
if (stagingDir !== null) {
|
|
6299
6468
|
try {
|
|
6300
|
-
fs9__namespace.rmSync(
|
|
6469
|
+
fs9__namespace.rmSync(stagingDir, { recursive: true, force: true });
|
|
6301
6470
|
} catch {
|
|
6302
6471
|
}
|
|
6303
6472
|
}
|
|
6304
6473
|
throw err;
|
|
6305
6474
|
} finally {
|
|
6475
|
+
removeIfEmpty(tmpDir);
|
|
6306
6476
|
releaseLock();
|
|
6307
6477
|
}
|
|
6308
6478
|
}
|