@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
|
@@ -2188,11 +2188,19 @@ function isSensitivePath(relativePath) {
|
|
|
2188
2188
|
}
|
|
2189
2189
|
return matchesSensitiveList(posixPath, base);
|
|
2190
2190
|
}
|
|
2191
|
-
|
|
2191
|
+
var activeSecretRules = null;
|
|
2192
|
+
function setActiveSecretRules(rules) {
|
|
2193
|
+
activeSecretRules = rules === null ? null : [...rules];
|
|
2194
|
+
}
|
|
2195
|
+
function pathScanRules(extraRules) {
|
|
2196
|
+
const fallback = extraRules ?? activeSecretRules ?? [];
|
|
2197
|
+
return [...DEFAULT_SECRET_PATTERNS, ...fallback];
|
|
2198
|
+
}
|
|
2199
|
+
function findSecretInPath(relativePath, extraRules) {
|
|
2192
2200
|
const posixPath = relativePath.replace(/\\/g, "/");
|
|
2193
2201
|
const spans = [];
|
|
2194
2202
|
const rules = [];
|
|
2195
|
-
for (const { rule, pattern } of
|
|
2203
|
+
for (const { rule, pattern } of pathScanRules(extraRules)) {
|
|
2196
2204
|
const scan = new RegExp(pattern.source, `${pattern.flags.replace(/[gy]/g, "")}g`);
|
|
2197
2205
|
let match;
|
|
2198
2206
|
while ((match = scan.exec(posixPath)) !== null) {
|
|
@@ -2200,24 +2208,34 @@ function findSecretInPath(relativePath) {
|
|
|
2200
2208
|
scan.lastIndex += 1;
|
|
2201
2209
|
continue;
|
|
2202
2210
|
}
|
|
2203
|
-
spans.push({ start: match.index, end: match.index + match[0].length
|
|
2211
|
+
spans.push({ start: match.index, end: match.index + match[0].length });
|
|
2204
2212
|
if (!rules.includes(rule)) rules.push(rule);
|
|
2205
2213
|
}
|
|
2206
2214
|
}
|
|
2207
2215
|
if (spans.length === 0) return null;
|
|
2208
2216
|
spans.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
2217
|
+
const merged = [];
|
|
2218
|
+
for (const span of spans) {
|
|
2219
|
+
const last = merged[merged.length - 1];
|
|
2220
|
+
if (last && span.start <= last.end) last.end = Math.max(last.end, span.end);
|
|
2221
|
+
else merged.push({ start: span.start, end: span.end });
|
|
2222
|
+
}
|
|
2209
2223
|
let out = "";
|
|
2210
2224
|
let cursor = 0;
|
|
2211
|
-
for (const span of
|
|
2212
|
-
|
|
2213
|
-
const start = Math.max(span.start, cursor);
|
|
2214
|
-
out += posixPath.slice(cursor, start);
|
|
2225
|
+
for (const span of merged) {
|
|
2226
|
+
out += posixPath.slice(cursor, span.start);
|
|
2215
2227
|
out += REDACTION_MARKER;
|
|
2216
|
-
cursor =
|
|
2228
|
+
cursor = span.end;
|
|
2217
2229
|
}
|
|
2218
2230
|
out += posixPath.slice(cursor);
|
|
2219
2231
|
return { rules, masked: out };
|
|
2220
2232
|
}
|
|
2233
|
+
function maskSkipPaths(records, extraRules) {
|
|
2234
|
+
return records.map((record) => {
|
|
2235
|
+
const hit = findSecretInPath(record.path, extraRules);
|
|
2236
|
+
return hit ? { ...record, path: hit.masked } : record;
|
|
2237
|
+
});
|
|
2238
|
+
}
|
|
2221
2239
|
function globToRegExp(glob) {
|
|
2222
2240
|
const normalized = glob.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+$/, "");
|
|
2223
2241
|
const anchored = normalized.startsWith("/");
|
|
@@ -2448,6 +2466,7 @@ function collectFiles(cwd, options = {}) {
|
|
|
2448
2466
|
const includePatterns = options.includePatterns ?? [];
|
|
2449
2467
|
const excludePatterns = options.excludePatterns ?? [];
|
|
2450
2468
|
const includeSensitiveFiles = options.includeSensitiveFiles ?? false;
|
|
2469
|
+
const pathRules = options.secretRules;
|
|
2451
2470
|
const isToolOwned = makeToolOwnedDecider(cwd);
|
|
2452
2471
|
let candidates;
|
|
2453
2472
|
const skipped = [];
|
|
@@ -2483,7 +2502,7 @@ function collectFiles(cwd, options = {}) {
|
|
|
2483
2502
|
}
|
|
2484
2503
|
}
|
|
2485
2504
|
} catch {
|
|
2486
|
-
const walked = walkDirectory(cwd, cwd, /* @__PURE__ */ new Set(), true);
|
|
2505
|
+
const walked = walkDirectory(cwd, cwd, rootRealFor(cwd), /* @__PURE__ */ new Set(), true);
|
|
2487
2506
|
candidates = walked.files;
|
|
2488
2507
|
skipped.push(...walked.skipped);
|
|
2489
2508
|
}
|
|
@@ -2521,7 +2540,7 @@ function collectFiles(cwd, options = {}) {
|
|
|
2521
2540
|
});
|
|
2522
2541
|
return false;
|
|
2523
2542
|
}
|
|
2524
|
-
const secret = findSecretInPath(file);
|
|
2543
|
+
const secret = findSecretInPath(file, pathRules);
|
|
2525
2544
|
if (secret) {
|
|
2526
2545
|
skipped.push({
|
|
2527
2546
|
path: secret.masked,
|
|
@@ -2532,30 +2551,29 @@ function collectFiles(cwd, options = {}) {
|
|
|
2532
2551
|
}
|
|
2533
2552
|
return true;
|
|
2534
2553
|
}).sort();
|
|
2535
|
-
return { files, skipped };
|
|
2554
|
+
return { files, skipped: maskSkipPaths(skipped, pathRules) };
|
|
2536
2555
|
}
|
|
2537
|
-
function
|
|
2538
|
-
const results = { files: [], skipped: [] };
|
|
2539
|
-
let realDir;
|
|
2540
|
-
try {
|
|
2541
|
-
realDir = fs9.realpathSync(dir);
|
|
2542
|
-
} catch {
|
|
2543
|
-
realDir = dir;
|
|
2544
|
-
}
|
|
2545
|
-
if (visited.has(realDir)) return results;
|
|
2546
|
-
visited.add(realDir);
|
|
2547
|
-
let rootReal;
|
|
2556
|
+
function rootRealFor(root) {
|
|
2548
2557
|
try {
|
|
2549
|
-
|
|
2558
|
+
return fs9.realpathSync(root);
|
|
2550
2559
|
} catch {
|
|
2551
|
-
|
|
2560
|
+
return root;
|
|
2552
2561
|
}
|
|
2562
|
+
}
|
|
2563
|
+
function walkDirectory(dir, baseDir, rootReal, visited, isRoot = false) {
|
|
2564
|
+
const results = { files: [], skipped: [] };
|
|
2565
|
+
if (visited.has(dir)) return results;
|
|
2566
|
+
visited.add(dir);
|
|
2553
2567
|
const ignoredByGitignore = isRoot ? readGitignoreMatcher(baseDir) : () => false;
|
|
2554
2568
|
let entries;
|
|
2555
2569
|
try {
|
|
2556
2570
|
entries = fs9.readdirSync(dir, { withFileTypes: true });
|
|
2557
2571
|
} catch {
|
|
2558
|
-
results.skipped.push({
|
|
2572
|
+
results.skipped.push({
|
|
2573
|
+
path: path10.relative(baseDir, dir).replace(/\\/g, "/") || ".",
|
|
2574
|
+
reason: "read-error",
|
|
2575
|
+
detail: "directory unreadable"
|
|
2576
|
+
});
|
|
2559
2577
|
return results;
|
|
2560
2578
|
}
|
|
2561
2579
|
for (const entry of entries) {
|
|
@@ -2634,7 +2652,7 @@ function walkDirectory(dir, baseDir, visited, isRoot = false) {
|
|
|
2634
2652
|
isFile = true;
|
|
2635
2653
|
}
|
|
2636
2654
|
if (isDirectory) {
|
|
2637
|
-
const nested = walkDirectory(fullPath, baseDir, visited);
|
|
2655
|
+
const nested = walkDirectory(fullPath, baseDir, rootReal, visited);
|
|
2638
2656
|
results.files.push(...nested.files);
|
|
2639
2657
|
results.skipped.push(...nested.skipped);
|
|
2640
2658
|
} else if (isFile) {
|
|
@@ -3226,6 +3244,7 @@ function resolveConfig(userConfig, cliOptions, baseDir) {
|
|
|
3226
3244
|
...aliasedRules ?? []
|
|
3227
3245
|
]);
|
|
3228
3246
|
const secretRules = disableDefaultPatterns ? compiledCustomRules : [...compileSecretRules(DEFAULT_SECRET_PATTERNS), ...compiledCustomRules];
|
|
3247
|
+
setActiveSecretRules(secretRules);
|
|
3229
3248
|
const cliMonolith = cliOptions?.includeMonolith;
|
|
3230
3249
|
const includeMonolith = cliMonolith ?? strictBoolean(userConfig?.includeMonolith, false, "`includeMonolith`");
|
|
3231
3250
|
const artifacts = resolveArtifacts(
|
|
@@ -3333,7 +3352,8 @@ function defineConfig(config) {
|
|
|
3333
3352
|
}
|
|
3334
3353
|
|
|
3335
3354
|
// src/generator/audit.ts
|
|
3336
|
-
function generateAuditReport(manifest, secretFindings) {
|
|
3355
|
+
function generateAuditReport(manifest, secretFindings, secretRules) {
|
|
3356
|
+
const mask = (value) => findSecretInPath(value, secretRules)?.masked ?? value;
|
|
3337
3357
|
const lines = [
|
|
3338
3358
|
"# Codebase Health & Security Audit",
|
|
3339
3359
|
"",
|
|
@@ -3368,7 +3388,7 @@ function generateAuditReport(manifest, secretFindings) {
|
|
|
3368
3388
|
"| :--- | :--- | :--- |"
|
|
3369
3389
|
);
|
|
3370
3390
|
for (const finding of secretFindings) {
|
|
3371
|
-
lines.push(`| \`${finding.path ?? "unknown"}\` | ${finding.line} | \`${finding.rule}\` |`);
|
|
3391
|
+
lines.push(`| \`${mask(finding.path ?? "unknown")}\` | ${finding.line} | \`${finding.rule}\` |`);
|
|
3372
3392
|
}
|
|
3373
3393
|
lines.push("", "### Matches by rule", "", "| Rule | Matches |", "| :--- | :--- |");
|
|
3374
3394
|
for (const [rule, count] of Array.from(byRule.entries()).sort((a, b) => b[1] - a[1])) {
|
|
@@ -3390,7 +3410,7 @@ function generateAuditReport(manifest, secretFindings) {
|
|
|
3390
3410
|
for (const file of largeFiles) {
|
|
3391
3411
|
const sizeKb = (file.sizeBytes / 1024).toFixed(1);
|
|
3392
3412
|
const status = file.isPreviewTruncated ? "Truncated Head/Tail" : "Full";
|
|
3393
|
-
lines.push(`| \`${file.relativePath}\` | ${sizeKb} KB | ${file.lines} | ${status} |`);
|
|
3413
|
+
lines.push(`| \`${mask(file.relativePath)}\` | ${sizeKb} KB | ${file.lines} | ${status} |`);
|
|
3394
3414
|
}
|
|
3395
3415
|
lines.push("");
|
|
3396
3416
|
}
|
|
@@ -3432,7 +3452,7 @@ function generateAuditReport(manifest, secretFindings) {
|
|
|
3432
3452
|
"| :--- | :--- | :--- |"
|
|
3433
3453
|
);
|
|
3434
3454
|
for (const skip of manifest.skipped) {
|
|
3435
|
-
lines.push(`| \`${skip.path}\` | \`${skip.reason}\` | ${skip.detail ?? "-"} |`);
|
|
3455
|
+
lines.push(`| \`${mask(skip.path)}\` | \`${skip.reason}\` | ${skip.detail ?? "-"} |`);
|
|
3436
3456
|
}
|
|
3437
3457
|
lines.push("");
|
|
3438
3458
|
}
|
|
@@ -4094,6 +4114,9 @@ function detectLanguage(filePath) {
|
|
|
4094
4114
|
const ext = path10.posix.extname(base).toLowerCase();
|
|
4095
4115
|
return LANGUAGE_BY_EXTENSION[ext] ?? "text";
|
|
4096
4116
|
}
|
|
4117
|
+
function maskedPath(value, secretRules) {
|
|
4118
|
+
return findSecretInPath(value, secretRules)?.masked ?? value;
|
|
4119
|
+
}
|
|
4097
4120
|
function emptyDrift() {
|
|
4098
4121
|
return {
|
|
4099
4122
|
missingInSnapshot: [],
|
|
@@ -4164,15 +4187,20 @@ function validateSnapshot(configInput) {
|
|
|
4164
4187
|
const skippedSet = new Set(
|
|
4165
4188
|
manifest.skipped.filter((entry) => entry && typeof entry.path === "string").map((entry) => entry.path)
|
|
4166
4189
|
);
|
|
4190
|
+
const isSkippedOnDisk = (diskFile) => {
|
|
4191
|
+
if (skippedSet.has(diskFile)) return true;
|
|
4192
|
+
return skippedSet.has(maskedPath(diskFile, config.secretRules));
|
|
4193
|
+
};
|
|
4167
4194
|
const collection = collectFiles(config.cwd, {
|
|
4168
4195
|
includePatterns: config.include,
|
|
4169
4196
|
excludePatterns: [...config.excludePatterns, ...config.presetExclude],
|
|
4170
|
-
includeSensitiveFiles: config.includeSensitiveFiles
|
|
4197
|
+
includeSensitiveFiles: config.includeSensitiveFiles,
|
|
4198
|
+
secretRules: config.secretRules
|
|
4171
4199
|
});
|
|
4172
4200
|
for (const diskFile of collection.files) {
|
|
4173
4201
|
const snapshotHash = manifestFileMap.get(diskFile);
|
|
4174
4202
|
if (!snapshotHash) {
|
|
4175
|
-
if (
|
|
4203
|
+
if (isSkippedOnDisk(diskFile) && !wouldNowBeIncluded(config.cwd, diskFile)) continue;
|
|
4176
4204
|
drift.missingInSnapshot.push(diskFile);
|
|
4177
4205
|
continue;
|
|
4178
4206
|
}
|
|
@@ -4441,10 +4469,19 @@ function validateSnapshot(configInput) {
|
|
|
4441
4469
|
`${drift.configMismatches.length} configuration mismatch(es) between the manifest and this run.`
|
|
4442
4470
|
);
|
|
4443
4471
|
}
|
|
4472
|
+
const maskedDrift = {
|
|
4473
|
+
...drift,
|
|
4474
|
+
missingInSnapshot: drift.missingInSnapshot.map((value) => maskedPath(value, config.secretRules)),
|
|
4475
|
+
missingOnDisk: drift.missingOnDisk.map((value) => maskedPath(value, config.secretRules)),
|
|
4476
|
+
hashMismatches: drift.hashMismatches.map((mismatch) => ({
|
|
4477
|
+
...mismatch,
|
|
4478
|
+
path: maskedPath(mismatch.path, config.secretRules)
|
|
4479
|
+
}))
|
|
4480
|
+
};
|
|
4444
4481
|
return {
|
|
4445
4482
|
valid: errors.length === 0,
|
|
4446
4483
|
manifestPresent: true,
|
|
4447
|
-
drift,
|
|
4484
|
+
drift: maskedDrift,
|
|
4448
4485
|
errors,
|
|
4449
4486
|
warnings
|
|
4450
4487
|
};
|
|
@@ -4479,18 +4516,22 @@ function readManifest2(config) {
|
|
|
4479
4516
|
function explainPath(config, target) {
|
|
4480
4517
|
const relative4 = normalizeTarget(config.cwd, target);
|
|
4481
4518
|
const absolute = path10.join(config.cwd, relative4);
|
|
4519
|
+
const maskedPath2 = findSecretInPath(relative4, config.secretRules)?.masked ?? relative4;
|
|
4482
4520
|
const result = {
|
|
4483
|
-
path:
|
|
4521
|
+
path: maskedPath2,
|
|
4484
4522
|
exists: fs9.existsSync(absolute),
|
|
4485
4523
|
included: false
|
|
4486
4524
|
};
|
|
4487
4525
|
const collection = collectFiles(config.cwd, {
|
|
4488
4526
|
includePatterns: config.include,
|
|
4489
4527
|
excludePatterns: [...config.excludePatterns, ...config.presetExclude],
|
|
4490
|
-
includeSensitiveFiles: config.includeSensitiveFiles
|
|
4528
|
+
includeSensitiveFiles: config.includeSensitiveFiles,
|
|
4529
|
+
secretRules: config.secretRules
|
|
4491
4530
|
});
|
|
4492
4531
|
if (!collection.files.includes(relative4)) {
|
|
4493
|
-
const record = collection.skipped.find(
|
|
4532
|
+
const record = collection.skipped.find(
|
|
4533
|
+
(entry2) => entry2.path === relative4 || entry2.path === maskedPath2
|
|
4534
|
+
);
|
|
4494
4535
|
if (record) {
|
|
4495
4536
|
result.reason = record.reason;
|
|
4496
4537
|
result.detail = record.detail;
|
|
@@ -4527,7 +4568,7 @@ function explainPath(config, target) {
|
|
|
4527
4568
|
result.secrets = findings.slice(0, 20).map((finding) => ({ rule: finding.rule, line: finding.line }));
|
|
4528
4569
|
}
|
|
4529
4570
|
const manifest = readManifest2(config);
|
|
4530
|
-
const entry = manifest?.files.find((file) => file.relativePath === relative4);
|
|
4571
|
+
const entry = Array.isArray(manifest?.files) ? manifest.files.find((file) => file.relativePath === relative4) : void 0;
|
|
4531
4572
|
result.part = entry?.part ?? null;
|
|
4532
4573
|
result.inclusionMode = entry?.inclusionMode;
|
|
4533
4574
|
return result;
|
|
@@ -4632,12 +4673,13 @@ function compareManifests(before, after) {
|
|
|
4632
4673
|
if (!right.has(filePath)) removed.push(filePath);
|
|
4633
4674
|
}
|
|
4634
4675
|
const sort = (values) => values.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
4676
|
+
const mask = (values) => values.map((value) => findSecretInPath(value)?.masked ?? value);
|
|
4635
4677
|
return {
|
|
4636
4678
|
before: side(before),
|
|
4637
4679
|
after: side(after),
|
|
4638
|
-
added: sort(added),
|
|
4639
|
-
removed: sort(removed),
|
|
4640
|
-
changed: sort(changed),
|
|
4680
|
+
added: mask(sort(added)),
|
|
4681
|
+
removed: mask(sort(removed)),
|
|
4682
|
+
changed: mask(sort(changed)),
|
|
4641
4683
|
unchanged
|
|
4642
4684
|
};
|
|
4643
4685
|
}
|
|
@@ -5362,7 +5404,7 @@ async function runInit(options) {
|
|
|
5362
5404
|
|
|
5363
5405
|
// src/index.ts
|
|
5364
5406
|
var GENERATOR_NAME = "@ankurhalder/codebase-snapshot";
|
|
5365
|
-
var GENERATOR_VERSION = "4.0.
|
|
5407
|
+
var GENERATOR_VERSION = "4.0.1";
|
|
5366
5408
|
var SCHEMA_VERSION = "3.0.0";
|
|
5367
5409
|
function sha256Hex2(input) {
|
|
5368
5410
|
return crypto.createHash("sha256").update(input).digest("hex");
|
|
@@ -5399,7 +5441,6 @@ function bump(counts, key) {
|
|
|
5399
5441
|
}
|
|
5400
5442
|
var RELATIVE_SPECIFIER = /^\.{1,2}\//;
|
|
5401
5443
|
var IMPORT_CANDIDATE_SUFFIXES = [
|
|
5402
|
-
"",
|
|
5403
5444
|
".ts",
|
|
5404
5445
|
".tsx",
|
|
5405
5446
|
".mts",
|
|
@@ -5413,23 +5454,59 @@ var IMPORT_CANDIDATE_SUFFIXES = [
|
|
|
5413
5454
|
"/index.js",
|
|
5414
5455
|
"/index.mjs"
|
|
5415
5456
|
];
|
|
5416
|
-
|
|
5457
|
+
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
5458
|
+
".ts",
|
|
5459
|
+
".tsx",
|
|
5460
|
+
".mts",
|
|
5461
|
+
".cts",
|
|
5462
|
+
".js",
|
|
5463
|
+
".jsx",
|
|
5464
|
+
".mjs",
|
|
5465
|
+
".cjs"
|
|
5466
|
+
]);
|
|
5467
|
+
function buildImportResolver(files) {
|
|
5468
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
5469
|
+
const byPathFolded = /* @__PURE__ */ new Map();
|
|
5470
|
+
const byStem = /* @__PURE__ */ new Map();
|
|
5471
|
+
const byStemFolded = /* @__PURE__ */ new Map();
|
|
5472
|
+
const remember = (map, key, value) => {
|
|
5473
|
+
if (!map.has(key)) map.set(key, value);
|
|
5474
|
+
};
|
|
5475
|
+
for (const file of files) {
|
|
5476
|
+
const relativePath = file.relativePath;
|
|
5477
|
+
remember(byPath, relativePath, relativePath);
|
|
5478
|
+
remember(byPathFolded, relativePath.toLowerCase(), relativePath);
|
|
5479
|
+
const extension = path10.posix.extname(relativePath);
|
|
5480
|
+
if (!SOURCE_EXTENSIONS.has(extension)) continue;
|
|
5481
|
+
const stem = relativePath.slice(0, -extension.length);
|
|
5482
|
+
remember(byStem, stem, relativePath);
|
|
5483
|
+
remember(byStemFolded, stem.toLowerCase(), relativePath);
|
|
5484
|
+
if (path10.posix.basename(stem) === "index") {
|
|
5485
|
+
const directory = path10.posix.dirname(stem);
|
|
5486
|
+
remember(byStem, directory, relativePath);
|
|
5487
|
+
remember(byStemFolded, directory.toLowerCase(), relativePath);
|
|
5488
|
+
}
|
|
5489
|
+
}
|
|
5490
|
+
return { byPath, byPathFolded, byStem, byStemFolded };
|
|
5491
|
+
}
|
|
5492
|
+
function resolveSpecifier(fromFile, specifier, resolver) {
|
|
5417
5493
|
if (!RELATIVE_SPECIFIER.test(specifier)) return null;
|
|
5418
|
-
const
|
|
5419
|
-
|
|
5420
|
-
|
|
5494
|
+
const joined = path10.posix.normalize(
|
|
5495
|
+
path10.posix.join(path10.posix.dirname(fromFile), specifier)
|
|
5496
|
+
);
|
|
5497
|
+
const exact = (key) => resolver.byPath.get(key) ?? resolver.byPathFolded.get(key.toLowerCase()) ?? null;
|
|
5498
|
+
const direct = exact(joined);
|
|
5499
|
+
if (direct) return direct;
|
|
5421
5500
|
for (const suffix of IMPORT_CANDIDATE_SUFFIXES) {
|
|
5422
|
-
const
|
|
5423
|
-
if (
|
|
5424
|
-
}
|
|
5425
|
-
const extensionSwap = new RegExp(`${candidate}\\.(?:ts|tsx|mts|cts|js|jsx|mjs|cjs)$`);
|
|
5426
|
-
for (const file of knownFiles) {
|
|
5427
|
-
if (extensionSwap.test(file)) return file;
|
|
5501
|
+
const hit = exact(`${joined}${suffix}`);
|
|
5502
|
+
if (hit) return hit;
|
|
5428
5503
|
}
|
|
5429
|
-
|
|
5504
|
+
const stem = joined.replace(/\.(?:js|mjs|cjs|jsx)$/, "");
|
|
5505
|
+
const byStem = (key) => resolver.byStem.get(key) ?? resolver.byStemFolded.get(key.toLowerCase()) ?? null;
|
|
5506
|
+
return byStem(joined) ?? byStem(stem);
|
|
5430
5507
|
}
|
|
5431
5508
|
function buildIndexes(files) {
|
|
5432
|
-
const
|
|
5509
|
+
const resolver = buildImportResolver(files);
|
|
5433
5510
|
const importerCounts = /* @__PURE__ */ new Map();
|
|
5434
5511
|
const byFile = files.filter((file) => isSourceSummary(file.summary)).map((file) => {
|
|
5435
5512
|
const summary = file.summary;
|
|
@@ -5441,7 +5518,7 @@ function buildIndexes(files) {
|
|
|
5441
5518
|
});
|
|
5442
5519
|
for (const entry of byFile) {
|
|
5443
5520
|
for (const specifier of entry.imports) {
|
|
5444
|
-
const resolved = resolveSpecifier(entry.path, specifier,
|
|
5521
|
+
const resolved = resolveSpecifier(entry.path, specifier, resolver);
|
|
5445
5522
|
if (resolved) importerCounts.set(resolved, (importerCounts.get(resolved) ?? 0) + 1);
|
|
5446
5523
|
}
|
|
5447
5524
|
}
|
|
@@ -5532,15 +5609,22 @@ function resolveSafeOutputDirs(config) {
|
|
|
5532
5609
|
return { outDir, tmpDir };
|
|
5533
5610
|
}
|
|
5534
5611
|
var PLACEHOLDER_ENTRIES = /* @__PURE__ */ new Set([".gitkeep", ".gitignore", ".DS_Store"]);
|
|
5535
|
-
var
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5612
|
+
var RUN_DIR_PREFIX = "run-";
|
|
5613
|
+
var STALE_RUN_MS = 60 * 60 * 1e3;
|
|
5614
|
+
function maskPathText(value, secretRules) {
|
|
5615
|
+
return findSecretInPath(value, secretRules)?.masked ?? value;
|
|
5616
|
+
}
|
|
5617
|
+
function maskSkipRecords(records, secretRules) {
|
|
5618
|
+
return maskSkipPaths(records, secretRules);
|
|
5619
|
+
}
|
|
5620
|
+
function isProcessAlive(pid) {
|
|
5621
|
+
try {
|
|
5622
|
+
process.kill(pid, 0);
|
|
5623
|
+
return true;
|
|
5624
|
+
} catch (err) {
|
|
5625
|
+
return err.code !== "ESRCH";
|
|
5626
|
+
}
|
|
5627
|
+
}
|
|
5544
5628
|
var OWNERSHIP_MARKER = ".codebase-snapshot";
|
|
5545
5629
|
var SUPPORTED_MARKER_SCHEMAS = /* @__PURE__ */ new Set([SCHEMA_VERSION]);
|
|
5546
5630
|
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;
|
|
@@ -5570,6 +5654,7 @@ function markerPayload(dir, state, id, createdAt) {
|
|
|
5570
5654
|
createdAt,
|
|
5571
5655
|
state,
|
|
5572
5656
|
id,
|
|
5657
|
+
pid: process.pid,
|
|
5573
5658
|
entries: listEntries(dir)
|
|
5574
5659
|
};
|
|
5575
5660
|
const manifestPath = path10.join(dir, "manifest.json");
|
|
@@ -5633,6 +5718,7 @@ function readOwnershipMarker(dir) {
|
|
|
5633
5718
|
createdAt: typeof candidate.createdAt === "string" ? candidate.createdAt : "unknown",
|
|
5634
5719
|
state: candidate.state,
|
|
5635
5720
|
id: candidate.id,
|
|
5721
|
+
pid: typeof candidate.pid === "number" ? candidate.pid : void 0,
|
|
5636
5722
|
manifestSha256: typeof candidate.manifestSha256 === "string" ? candidate.manifestSha256 : void 0,
|
|
5637
5723
|
entries: Array.isArray(candidate.entries) && candidate.entries.every((entry) => typeof entry === "string") ? candidate.entries : void 0
|
|
5638
5724
|
},
|
|
@@ -5740,7 +5826,7 @@ function describeEntries(entries, limit = 5) {
|
|
|
5740
5826
|
const shown = entries.slice(0, limit).join(", ");
|
|
5741
5827
|
return entries.length > limit ? `${shown}, and ${entries.length - limit} more` : shown;
|
|
5742
5828
|
}
|
|
5743
|
-
function assertReplaceable(target, label) {
|
|
5829
|
+
function assertReplaceable(target, label, secretRules) {
|
|
5744
5830
|
if (!fs9.existsSync(target)) return;
|
|
5745
5831
|
if (!fs9.statSync(target).isDirectory()) {
|
|
5746
5832
|
throw new Error(
|
|
@@ -5749,34 +5835,89 @@ function assertReplaceable(target, label) {
|
|
|
5749
5835
|
}
|
|
5750
5836
|
const entries = fs9.readdirSync(target);
|
|
5751
5837
|
if (entries.length === 0) return;
|
|
5752
|
-
if (
|
|
5753
|
-
const {
|
|
5754
|
-
if (label === "tmpDir") {
|
|
5755
|
-
if (!marker2) {
|
|
5756
|
-
throw new Error(
|
|
5757
|
-
`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.`
|
|
5758
|
-
);
|
|
5759
|
-
}
|
|
5760
|
-
const unexpected = entries.filter((name) => !STAGING_ENTRIES.has(name));
|
|
5761
|
-
if (unexpected.length > 0) {
|
|
5762
|
-
throw new Error(
|
|
5763
|
-
`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.`
|
|
5764
|
-
);
|
|
5765
|
-
}
|
|
5766
|
-
return;
|
|
5767
|
-
}
|
|
5838
|
+
if (entries.every((name) => PLACEHOLDER_ENTRIES.has(name))) return;
|
|
5839
|
+
const { problem } = readOwnershipMarker(target);
|
|
5768
5840
|
const verdict = assessSnapshotDirectory(target);
|
|
5769
5841
|
if (verdict.owned) return;
|
|
5842
|
+
const shownForeign = verdict.foreignEntries.map((name) => maskPathText(name, secretRules));
|
|
5843
|
+
const shownEntries = entries.map((name) => maskPathText(name, secretRules));
|
|
5770
5844
|
if (verdict.foreignEntries.length > 0) {
|
|
5771
5845
|
throw new Error(
|
|
5772
|
-
`Refusing to replace ${label} ${target}: it carries this generator's ownership marker, but these entries are not part of the snapshot it recorded: ${describeEntries(
|
|
5846
|
+
`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.`
|
|
5773
5847
|
);
|
|
5774
5848
|
}
|
|
5775
5849
|
const reason = verdict.problem ?? problem ?? "it does not look like a snapshot this generator wrote";
|
|
5776
5850
|
throw new Error(
|
|
5777
|
-
`Refusing to replace ${label} ${target}: ${reason} (found ${describeEntries(
|
|
5851
|
+
`Refusing to replace ${label} ${target}: ${reason} (found ${describeEntries(shownEntries)}). Remove the directory yourself, or point ${label} at a new or empty directory.`
|
|
5778
5852
|
);
|
|
5779
5853
|
}
|
|
5854
|
+
function assertStagingRootUsable(tmpDir, secretRules) {
|
|
5855
|
+
if (!fs9.existsSync(tmpDir)) return;
|
|
5856
|
+
if (!fs9.statSync(tmpDir).isDirectory()) {
|
|
5857
|
+
throw new Error(`Refusing to write into tmpDir ${tmpDir}: it exists but is not a directory.`);
|
|
5858
|
+
}
|
|
5859
|
+
const entries = fs9.readdirSync(tmpDir);
|
|
5860
|
+
if (entries.length === 0) return;
|
|
5861
|
+
const foreign = entries.filter((name) => {
|
|
5862
|
+
const full = path10.join(tmpDir, name);
|
|
5863
|
+
if (!name.startsWith(RUN_DIR_PREFIX)) return true;
|
|
5864
|
+
let stats;
|
|
5865
|
+
try {
|
|
5866
|
+
stats = fs9.statSync(full);
|
|
5867
|
+
} catch {
|
|
5868
|
+
return true;
|
|
5869
|
+
}
|
|
5870
|
+
if (!stats.isDirectory()) return true;
|
|
5871
|
+
const { marker: marker2 } = readOwnershipMarker(full);
|
|
5872
|
+
if (marker2) return false;
|
|
5873
|
+
try {
|
|
5874
|
+
return fs9.readdirSync(full).length > 0;
|
|
5875
|
+
} catch {
|
|
5876
|
+
return true;
|
|
5877
|
+
}
|
|
5878
|
+
});
|
|
5879
|
+
if (foreign.length > 0) {
|
|
5880
|
+
const shown = describeEntries(foreign.map((name) => maskPathText(name, secretRules)));
|
|
5881
|
+
throw new Error(
|
|
5882
|
+
`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.`
|
|
5883
|
+
);
|
|
5884
|
+
}
|
|
5885
|
+
}
|
|
5886
|
+
function cleanStaleRunDirs(tmpDir) {
|
|
5887
|
+
let entries;
|
|
5888
|
+
try {
|
|
5889
|
+
entries = fs9.readdirSync(tmpDir);
|
|
5890
|
+
} catch {
|
|
5891
|
+
return;
|
|
5892
|
+
}
|
|
5893
|
+
for (const name of entries) {
|
|
5894
|
+
if (!name.startsWith(RUN_DIR_PREFIX)) continue;
|
|
5895
|
+
const full = path10.join(tmpDir, name);
|
|
5896
|
+
const { marker: marker2 } = readOwnershipMarker(full);
|
|
5897
|
+
if (marker2) {
|
|
5898
|
+
const created = Date.parse(marker2.createdAt);
|
|
5899
|
+
const aged = !Number.isFinite(created) || Date.now() - created > STALE_RUN_MS;
|
|
5900
|
+
const abandoned = typeof marker2.pid === "number" && !isProcessAlive(marker2.pid);
|
|
5901
|
+
if (aged || abandoned) {
|
|
5902
|
+
try {
|
|
5903
|
+
fs9.rmSync(full, { recursive: true, force: true });
|
|
5904
|
+
} catch {
|
|
5905
|
+
}
|
|
5906
|
+
}
|
|
5907
|
+
continue;
|
|
5908
|
+
}
|
|
5909
|
+
try {
|
|
5910
|
+
if (fs9.readdirSync(full).length === 0) fs9.rmSync(full, { recursive: true, force: true });
|
|
5911
|
+
} catch {
|
|
5912
|
+
}
|
|
5913
|
+
}
|
|
5914
|
+
}
|
|
5915
|
+
function removeIfEmpty(dir) {
|
|
5916
|
+
try {
|
|
5917
|
+
if (fs9.readdirSync(dir).length === 0) fs9.rmSync(dir, { recursive: true, force: true });
|
|
5918
|
+
} catch {
|
|
5919
|
+
}
|
|
5920
|
+
}
|
|
5780
5921
|
function ensureParentDirectory(target, label) {
|
|
5781
5922
|
const parent = path10.dirname(target);
|
|
5782
5923
|
if (fs9.existsSync(parent) && !fs9.statSync(parent).isDirectory()) {
|
|
@@ -5792,14 +5933,12 @@ function ensureParentDirectory(target, label) {
|
|
|
5792
5933
|
);
|
|
5793
5934
|
}
|
|
5794
5935
|
}
|
|
5795
|
-
function acquireRunLock(
|
|
5796
|
-
const
|
|
5797
|
-
|
|
5798
|
-
`codebase-snapshot-${sha256Hex2(outDir).slice(0, 16)}.lock`
|
|
5799
|
-
);
|
|
5936
|
+
function acquireRunLock(stagingRoot) {
|
|
5937
|
+
const key = lockKeyFor(stagingRoot);
|
|
5938
|
+
const lockPath = path10.join(os.tmpdir(), `codebase-snapshot-${key}.lock`);
|
|
5800
5939
|
const payload = `${JSON.stringify({
|
|
5801
5940
|
pid: process.pid,
|
|
5802
|
-
|
|
5941
|
+
stagingRoot,
|
|
5803
5942
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5804
5943
|
})}
|
|
5805
5944
|
`;
|
|
@@ -5824,11 +5963,20 @@ function acquireRunLock(outDir) {
|
|
|
5824
5963
|
continue;
|
|
5825
5964
|
}
|
|
5826
5965
|
throw new Error(
|
|
5827
|
-
`Another generate run is already
|
|
5966
|
+
`Another generate run is already using the staging directory ${stagingRoot}. Wait for it to finish, or delete ${lockPath} if no other run is active.`
|
|
5828
5967
|
);
|
|
5829
5968
|
}
|
|
5830
5969
|
}
|
|
5831
|
-
throw new Error(`Could not acquire the generate lock for ${
|
|
5970
|
+
throw new Error(`Could not acquire the generate lock for ${stagingRoot}.`);
|
|
5971
|
+
}
|
|
5972
|
+
function lockKeyFor(stagingRoot) {
|
|
5973
|
+
let key = stagingRoot;
|
|
5974
|
+
try {
|
|
5975
|
+
key = fs9.realpathSync(stagingRoot);
|
|
5976
|
+
} catch {
|
|
5977
|
+
}
|
|
5978
|
+
if (process.platform === "win32" || process.platform === "darwin") key = key.toLowerCase();
|
|
5979
|
+
return sha256Hex2(key).slice(0, 16);
|
|
5832
5980
|
}
|
|
5833
5981
|
function lockOwnerIsGone(lockPath) {
|
|
5834
5982
|
let raw;
|
|
@@ -5864,18 +6012,32 @@ function writeManifestAtomically(manifestPath, manifest) {
|
|
|
5864
6012
|
throw err;
|
|
5865
6013
|
}
|
|
5866
6014
|
}
|
|
5867
|
-
function swapIntoPlace(
|
|
6015
|
+
function swapIntoPlace(stagingDir, outDir) {
|
|
5868
6016
|
ensureParentDirectory(outDir, "outDir");
|
|
6017
|
+
const deadline = Date.now() + 3e3;
|
|
6018
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
6019
|
+
try {
|
|
6020
|
+
swapOnce(stagingDir, outDir);
|
|
6021
|
+
return;
|
|
6022
|
+
} catch (err) {
|
|
6023
|
+
const code = err.code;
|
|
6024
|
+
const racy = code === "ENOENT" || code === "ENOTEMPTY" || code === "EEXIST" || code === "EPERM";
|
|
6025
|
+
if (!racy || attempt >= 10 || Date.now() > deadline) throw err;
|
|
6026
|
+
sleepSync(50);
|
|
6027
|
+
}
|
|
6028
|
+
}
|
|
6029
|
+
}
|
|
6030
|
+
function swapOnce(stagingDir, outDir) {
|
|
5869
6031
|
const backupDir = `${outDir}.backup-${process.pid}-${Date.now()}`;
|
|
5870
6032
|
const hadPrevious = fs9.existsSync(outDir);
|
|
5871
6033
|
if (hadPrevious) fs9.renameSync(outDir, backupDir);
|
|
5872
6034
|
try {
|
|
5873
6035
|
try {
|
|
5874
|
-
fs9.renameSync(
|
|
6036
|
+
fs9.renameSync(stagingDir, outDir);
|
|
5875
6037
|
} catch (err) {
|
|
5876
6038
|
if (err.code === "EXDEV") {
|
|
5877
|
-
fs9.cpSync(
|
|
5878
|
-
fs9.rmSync(
|
|
6039
|
+
fs9.cpSync(stagingDir, outDir, { recursive: true });
|
|
6040
|
+
fs9.rmSync(stagingDir, { recursive: true, force: true });
|
|
5879
6041
|
} else {
|
|
5880
6042
|
throw err;
|
|
5881
6043
|
}
|
|
@@ -5889,6 +6051,10 @@ function swapIntoPlace(tmpDir, outDir) {
|
|
|
5889
6051
|
throw err;
|
|
5890
6052
|
}
|
|
5891
6053
|
}
|
|
6054
|
+
function sleepSync(milliseconds) {
|
|
6055
|
+
const buffer = new Int32Array(new SharedArrayBuffer(4));
|
|
6056
|
+
Atomics.wait(buffer, 0, 0, milliseconds);
|
|
6057
|
+
}
|
|
5892
6058
|
function artifactWarnings(artifacts) {
|
|
5893
6059
|
const messages = [];
|
|
5894
6060
|
if (!artifacts.manifest) {
|
|
@@ -5951,11 +6117,12 @@ function generateSnapshot(configInput, options) {
|
|
|
5951
6117
|
const collection = collectFiles(config.cwd, {
|
|
5952
6118
|
includePatterns: config.include,
|
|
5953
6119
|
excludePatterns: [...config.excludePatterns, ...config.presetExclude],
|
|
5954
|
-
includeSensitiveFiles: config.includeSensitiveFiles
|
|
6120
|
+
includeSensitiveFiles: config.includeSensitiveFiles,
|
|
6121
|
+
secretRules: config.secretRules
|
|
5955
6122
|
});
|
|
5956
6123
|
const files = [];
|
|
5957
6124
|
const monolithBodies = /* @__PURE__ */ new Map();
|
|
5958
|
-
const skipped = [...collection.skipped];
|
|
6125
|
+
const skipped = maskSkipRecords([...collection.skipped], config.secretRules);
|
|
5959
6126
|
const secretFindings = [];
|
|
5960
6127
|
const warnings = [];
|
|
5961
6128
|
const layerCounts = {};
|
|
@@ -6029,12 +6196,12 @@ function generateSnapshot(configInput, options) {
|
|
|
6029
6196
|
summaryQuality = outcome?.quality;
|
|
6030
6197
|
if (isSourceSummary(summary) && summary.parseErrors) {
|
|
6031
6198
|
warnings.push(
|
|
6032
|
-
`Parse errors in ${relativePath} (${summary.parseErrors}); its summary is incomplete.`
|
|
6199
|
+
`Parse errors in ${maskPathText(relativePath, config.secretRules)} (${summary.parseErrors}); its summary is incomplete.`
|
|
6033
6200
|
);
|
|
6034
6201
|
}
|
|
6035
6202
|
} catch (err) {
|
|
6036
6203
|
warnings.push(
|
|
6037
|
-
`Summary skipped for ${relativePath}: ${err.message}`.replace(/\s+/g, " ")
|
|
6204
|
+
`Summary skipped for ${maskPathText(relativePath, config.secretRules)}: ${err.message}`.replace(/\s+/g, " ")
|
|
6038
6205
|
);
|
|
6039
6206
|
}
|
|
6040
6207
|
files.push({
|
|
@@ -6143,12 +6310,12 @@ function generateSnapshot(configInput, options) {
|
|
|
6143
6310
|
const { content: _content, ...rest } = file;
|
|
6144
6311
|
return rest;
|
|
6145
6312
|
}),
|
|
6146
|
-
skipped,
|
|
6313
|
+
skipped: maskSkipRecords(skipped, config.secretRules),
|
|
6147
6314
|
warnings
|
|
6148
6315
|
};
|
|
6149
6316
|
manifest.warnings = [
|
|
6150
6317
|
...warnings,
|
|
6151
|
-
...secretFindings.map((finding) => `${finding.rule} at ${finding.path ?? "unknown"}:${finding.line}`)
|
|
6318
|
+
...secretFindings.map((finding) => `${finding.rule} at ${maskPathText(finding.path ?? "unknown", config.secretRules)}:${finding.line}`)
|
|
6152
6319
|
];
|
|
6153
6320
|
manifest.totals.warningCount = manifest.warnings.length;
|
|
6154
6321
|
let monolithJson = null;
|
|
@@ -6194,31 +6361,33 @@ function generateSnapshot(configInput, options) {
|
|
|
6194
6361
|
manifest.totals.warningCount = manifest.warnings.length;
|
|
6195
6362
|
const { outDir, tmpDir } = resolveSafeOutputDirs(config);
|
|
6196
6363
|
const { artifacts } = config;
|
|
6197
|
-
assertReplaceable(
|
|
6198
|
-
|
|
6364
|
+
assertReplaceable(outDir, "outDir", config.secretRules);
|
|
6365
|
+
assertStagingRootUsable(tmpDir, config.secretRules);
|
|
6199
6366
|
if (dryRun) {
|
|
6200
6367
|
runAfterGenerate(config, manifest);
|
|
6201
6368
|
return manifest;
|
|
6202
6369
|
}
|
|
6203
|
-
const releaseLock = acquireRunLock(
|
|
6204
|
-
let
|
|
6370
|
+
const releaseLock = acquireRunLock(tmpDir);
|
|
6371
|
+
let stagingDir = null;
|
|
6205
6372
|
try {
|
|
6206
6373
|
ensureParentDirectory(outDir, "outDir");
|
|
6207
|
-
fs9.rmSync(tmpDir, { recursive: true, force: true });
|
|
6208
6374
|
fs9.mkdirSync(tmpDir, { recursive: true });
|
|
6209
|
-
|
|
6375
|
+
cleanStaleRunDirs(tmpDir);
|
|
6210
6376
|
const snapshotId = crypto.randomUUID();
|
|
6211
6377
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6212
|
-
|
|
6378
|
+
stagingDir = path10.join(tmpDir, `${RUN_DIR_PREFIX}${process.pid}-${snapshotId.slice(0, 8)}`);
|
|
6379
|
+
fs9.mkdirSync(stagingDir);
|
|
6380
|
+
writeOwnershipMarker(stagingDir, {
|
|
6213
6381
|
generator: GENERATOR_NAME,
|
|
6214
6382
|
version: GENERATOR_VERSION,
|
|
6215
6383
|
schemaVersion: SCHEMA_VERSION,
|
|
6216
6384
|
createdAt,
|
|
6217
6385
|
state: "staging",
|
|
6218
|
-
id: snapshotId
|
|
6386
|
+
id: snapshotId,
|
|
6387
|
+
pid: process.pid
|
|
6219
6388
|
});
|
|
6220
|
-
const partsDir = path10.join(
|
|
6221
|
-
const reportsDir = path10.join(
|
|
6389
|
+
const partsDir = path10.join(stagingDir, "parts");
|
|
6390
|
+
const reportsDir = path10.join(stagingDir, "reports");
|
|
6222
6391
|
if (artifacts.parts) fs9.mkdirSync(partsDir, { recursive: true });
|
|
6223
6392
|
if (artifacts.navigation || artifacts.projectTree || artifacts.audit) {
|
|
6224
6393
|
fs9.mkdirSync(reportsDir, { recursive: true });
|
|
@@ -6238,25 +6407,25 @@ function generateSnapshot(configInput, options) {
|
|
|
6238
6407
|
if (artifacts.audit) {
|
|
6239
6408
|
fs9.writeFileSync(
|
|
6240
6409
|
path10.join(reportsDir, "audit.md"),
|
|
6241
|
-
generateAuditReport(manifest, secretFindings),
|
|
6410
|
+
generateAuditReport(manifest, secretFindings, config.secretRules),
|
|
6242
6411
|
"utf8"
|
|
6243
6412
|
);
|
|
6244
6413
|
}
|
|
6245
6414
|
if (artifacts.readme) {
|
|
6246
|
-
fs9.writeFileSync(path10.join(
|
|
6415
|
+
fs9.writeFileSync(path10.join(stagingDir, "README.md"), generateReadme(manifest), "utf8");
|
|
6247
6416
|
}
|
|
6248
6417
|
if (artifacts.manifest) {
|
|
6249
|
-
fs9.writeFileSync(path10.join(
|
|
6418
|
+
fs9.writeFileSync(path10.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
|
|
6250
6419
|
}
|
|
6251
6420
|
if (monolithJson !== null) {
|
|
6252
|
-
fs9.writeFileSync(path10.join(
|
|
6421
|
+
fs9.writeFileSync(path10.join(stagingDir, "full-codebase.json"), monolithJson, "utf8");
|
|
6253
6422
|
}
|
|
6254
6423
|
if (monolithMarkdown !== null) {
|
|
6255
|
-
fs9.writeFileSync(path10.join(
|
|
6424
|
+
fs9.writeFileSync(path10.join(stagingDir, "full-codebase.md"), monolithMarkdown, "utf8");
|
|
6256
6425
|
}
|
|
6257
|
-
writeOwnershipMarker(
|
|
6258
|
-
swapIntoPlace(
|
|
6259
|
-
|
|
6426
|
+
writeOwnershipMarker(stagingDir, markerPayload(stagingDir, "complete", snapshotId, createdAt));
|
|
6427
|
+
swapIntoPlace(stagingDir, outDir);
|
|
6428
|
+
stagingDir = null;
|
|
6260
6429
|
const warningsBeforeHook = manifest.warnings.length;
|
|
6261
6430
|
runAfterGenerate(config, manifest);
|
|
6262
6431
|
if (artifacts.manifest && manifest.warnings.length !== warningsBeforeHook) {
|
|
@@ -6265,14 +6434,15 @@ function generateSnapshot(configInput, options) {
|
|
|
6265
6434
|
writeOwnershipMarker(outDir, markerPayload(outDir, "complete", snapshotId, createdAt));
|
|
6266
6435
|
return manifest;
|
|
6267
6436
|
} catch (err) {
|
|
6268
|
-
if (
|
|
6437
|
+
if (stagingDir !== null) {
|
|
6269
6438
|
try {
|
|
6270
|
-
fs9.rmSync(
|
|
6439
|
+
fs9.rmSync(stagingDir, { recursive: true, force: true });
|
|
6271
6440
|
} catch {
|
|
6272
6441
|
}
|
|
6273
6442
|
}
|
|
6274
6443
|
throw err;
|
|
6275
6444
|
} finally {
|
|
6445
|
+
removeIfEmpty(tmpDir);
|
|
6276
6446
|
releaseLock();
|
|
6277
6447
|
}
|
|
6278
6448
|
}
|
|
@@ -6281,5 +6451,5 @@ async function generateSnapshotAsync(configInput, options) {
|
|
|
6281
6451
|
}
|
|
6282
6452
|
|
|
6283
6453
|
export { ARTIFACT_NAMES, DEFAULT_ANSWERS, DEFAULT_SECRET_PATTERNS, GENERATOR_NAME, GENERATOR_VERSION, LANGUAGE_PROFILES, MIN_MAX_PART_BYTES, PRESETS, PromptCancelled, SCHEMA_VERSION, anchorForPath, assertReplaceable, assertUsableConfigInput, collectFiles, compareManifests, countLines, defineConfig, detectLanguage, detectPreset, explainPath, fenceForContent, fenceForText, generateProjectTree, generateSnapshot, generateSnapshotAsync, getPreset, globToRegExp, isBinaryBuffer, isBinaryExtension, isBinaryFile, isInteractive, isResolvedConfig, isSensitivePath, listPresetNames, loadConfigFile, loadConfigFileDetailed, loadManifest, markResolvedConfig, matchRule, matchesExclude, normalizeResolvedConfig, parseByteSize, partitionFiles, profileForPath, renderConfig, renderDiffText, renderExplainText, renderMinimalConfig, renumberParts, resolveConfig, resolveSafeOutputDirs, runInit, scanAndRedactSecrets, stripJsonComments, summarizeJson, summarizeMarkdown, summarizeTypeScriptSource, summarizeWithProfile, supportsTypeScriptImports, truncatePreview, truncateToBytes, unknownPresetMessage, validateSnapshot };
|
|
6284
|
-
//# sourceMappingURL=chunk-
|
|
6285
|
-
//# sourceMappingURL=chunk-
|
|
6454
|
+
//# sourceMappingURL=chunk-RGIMMEAW.js.map
|
|
6455
|
+
//# sourceMappingURL=chunk-RGIMMEAW.js.map
|