codebase-snapshot 0.9.12 → 0.9.14
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/CHANGELOG.md +379 -0
- package/README.md +1 -1
- package/dist/bin.js +1313 -633
- package/dist/{chunk-3H45YMBG.js → chunk-DUZK5VL2.js} +1413 -767
- package/dist/{chunk-5OR3WVPW.js → chunk-J4W74N4Y.js} +144 -44
- package/dist/cli.cjs +1305 -628
- package/dist/cli.d.cts +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +43 -54
- package/dist/{generate-worker-D5Xgh27c.d.cts → generate-worker-D_mUjgXw.d.cts} +21 -5
- package/dist/{generate-worker-D5Xgh27c.d.ts → generate-worker-D_mUjgXw.d.ts} +21 -5
- package/dist/index.cjs +1389 -760
- package/dist/index.d.cts +58 -35
- package/dist/index.d.ts +58 -35
- package/dist/index.js +1 -1
- package/dist/mcp.cjs +973 -405
- package/dist/mcp.d.cts +67 -67
- package/dist/mcp.d.ts +67 -67
- package/dist/mcp.js +2 -2
- package/dist/{types-CTewen3J.d.cts → types-DIX6zWSt.d.cts} +15 -0
- package/dist/{types-CTewen3J.d.ts → types-DIX6zWSt.d.ts} +15 -0
- package/docs/cli.md +8 -6
- package/docs/configuration.md +44 -10
- package/docs/mcp.md +16 -3
- package/docs/output.md +13 -0
- package/package.json +1 -1
package/dist/mcp.cjs
CHANGED
|
@@ -7,7 +7,7 @@ var crypto2 = require('crypto');
|
|
|
7
7
|
var module$1 = require('module');
|
|
8
8
|
var url = require('url');
|
|
9
9
|
var childProcess = require('child_process');
|
|
10
|
-
require('async_hooks');
|
|
10
|
+
var async_hooks = require('async_hooks');
|
|
11
11
|
require('os');
|
|
12
12
|
var worker_threads = require('worker_threads');
|
|
13
13
|
|
|
@@ -660,13 +660,23 @@ function summarizeTypeScriptSource(relativePath, content) {
|
|
|
660
660
|
if (ts__default.default.isImportDeclaration(node) && ts__default.default.isStringLiteral(node.moduleSpecifier)) {
|
|
661
661
|
summary.imports.push(node.moduleSpecifier.text);
|
|
662
662
|
}
|
|
663
|
+
if (ts__default.default.isImportEqualsDeclaration(node) && ts__default.default.isExternalModuleReference(node.moduleReference) && node.moduleReference.expression !== void 0 && ts__default.default.isStringLiteral(node.moduleReference.expression)) {
|
|
664
|
+
summary.imports.push(node.moduleReference.expression.text);
|
|
665
|
+
}
|
|
666
|
+
if (ts__default.default.isCallExpression(node) && node.arguments.length >= 1) {
|
|
667
|
+
const firstArgument = node.arguments[0];
|
|
668
|
+
if (firstArgument !== void 0 && ts__default.default.isStringLiteral(firstArgument)) {
|
|
669
|
+
const isDynamicImport = node.expression.kind === ts__default.default.SyntaxKind.ImportKeyword;
|
|
670
|
+
const isRequire = ts__default.default.isIdentifier(node.expression) && node.expression.text === "require";
|
|
671
|
+
if (isDynamicImport || isRequire) summary.imports.push(firstArgument.text);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
663
674
|
if (ts__default.default.isExportDeclaration(node)) {
|
|
664
675
|
if (node.moduleSpecifier && ts__default.default.isStringLiteral(node.moduleSpecifier)) {
|
|
665
676
|
summary.imports.push(node.moduleSpecifier.text);
|
|
677
|
+
summary.reExports.push(node.moduleSpecifier.text);
|
|
666
678
|
if (node.exportClause && ts__default.default.isNamespaceExport(node.exportClause)) {
|
|
667
679
|
summary.exports.push(node.exportClause.name.text);
|
|
668
|
-
} else if (!node.exportClause) {
|
|
669
|
-
summary.reExports.push(node.moduleSpecifier.text);
|
|
670
680
|
}
|
|
671
681
|
}
|
|
672
682
|
if (node.exportClause && ts__default.default.isNamedExports(node.exportClause)) {
|
|
@@ -811,7 +821,7 @@ function isCapitalizedName(name) {
|
|
|
811
821
|
}
|
|
812
822
|
|
|
813
823
|
// src/ast/profiles/cfamily.ts
|
|
814
|
-
var INCLUDE = /^#\s*include\s*[<"]([^>"]+)[>"]/;
|
|
824
|
+
var INCLUDE = /^#\s*include\s*([<"])([^>"]+)[>"]/;
|
|
815
825
|
var DEFINE = /^#\s*define\s+([A-Za-z_]\w*)/;
|
|
816
826
|
var USING = /^using\s+(?:namespace\s+)?([\w:]+)\s*;/;
|
|
817
827
|
var TYPE_DECL = /^(?:typedef\s+)?(?:struct|union|class|enum)\s+([A-Za-z_]\w*)/;
|
|
@@ -830,7 +840,7 @@ var cfamilyProfile = {
|
|
|
830
840
|
}
|
|
831
841
|
const included = INCLUDE.exec(trimmed);
|
|
832
842
|
if (included) {
|
|
833
|
-
summary.imports.push(included[1]);
|
|
843
|
+
summary.imports.push(included[1] === '"' ? `./${included[2]}` : included[2]);
|
|
834
844
|
return;
|
|
835
845
|
}
|
|
836
846
|
const used = USING.exec(trimmed);
|
|
@@ -1234,7 +1244,15 @@ var pythonProfile = {
|
|
|
1234
1244
|
}
|
|
1235
1245
|
const from = FROM_IMPORT.exec(trimmed);
|
|
1236
1246
|
if (from) {
|
|
1237
|
-
|
|
1247
|
+
const module = from[1];
|
|
1248
|
+
if (/^\.+$/.test(module)) {
|
|
1249
|
+
for (const name of from[2].split(",")) {
|
|
1250
|
+
const imported2 = name.replace(/[()]/g, "").trim().split(/\s+as\s+/)[0].trim();
|
|
1251
|
+
if (/^[A-Za-z_]\w*$/.test(imported2)) summary.imports.push(`${module}${imported2}`);
|
|
1252
|
+
}
|
|
1253
|
+
} else {
|
|
1254
|
+
summary.imports.push(module);
|
|
1255
|
+
}
|
|
1238
1256
|
routePending = false;
|
|
1239
1257
|
return;
|
|
1240
1258
|
}
|
|
@@ -1283,7 +1301,8 @@ var pythonProfile = {
|
|
|
1283
1301
|
};
|
|
1284
1302
|
|
|
1285
1303
|
// src/ast/profiles/ruby.ts
|
|
1286
|
-
var
|
|
1304
|
+
var REQUIRE_RELATIVE = /^require_relative\s+["']([^"']+)["']/;
|
|
1305
|
+
var REQUIRE = /^require\s+["']([^"']+)["']/;
|
|
1287
1306
|
var CLASS_OR_MODULE = /^(?:class|module)\s+([A-Z][\w:]*)/;
|
|
1288
1307
|
var METHOD3 = /^def\s+(?:self\.)?([A-Za-z_]\w*[?!=]?)/;
|
|
1289
1308
|
var rubyProfile = {
|
|
@@ -1294,6 +1313,11 @@ var rubyProfile = {
|
|
|
1294
1313
|
eachLine(content, (line) => {
|
|
1295
1314
|
const trimmed = line.trim();
|
|
1296
1315
|
if (!trimmed || trimmed.startsWith("#")) return;
|
|
1316
|
+
const relative8 = REQUIRE_RELATIVE.exec(trimmed);
|
|
1317
|
+
if (relative8) {
|
|
1318
|
+
summary.imports.push(`./${relative8[1]}`);
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1297
1321
|
const required = REQUIRE.exec(trimmed);
|
|
1298
1322
|
if (required) {
|
|
1299
1323
|
summary.imports.push(required[1]);
|
|
@@ -1384,7 +1408,8 @@ var rustProfile = {
|
|
|
1384
1408
|
};
|
|
1385
1409
|
|
|
1386
1410
|
// src/ast/profiles/sfc.ts
|
|
1387
|
-
var SCRIPT_BLOCK = /<script[^>]
|
|
1411
|
+
var SCRIPT_BLOCK = /<script([^>]*)>([\s\S]*?)<\/script>/gi;
|
|
1412
|
+
var JSX_LANG = /\blang\s*=\s*["']?[tj]sx\b/i;
|
|
1388
1413
|
var ASTRO_FRONTMATTER = /^\uFEFF?---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*(?=\r?\n|$)/;
|
|
1389
1414
|
function componentName(path14) {
|
|
1390
1415
|
const base = path14.split("/").pop() ?? path14;
|
|
@@ -1395,13 +1420,15 @@ var sfcProfile = {
|
|
|
1395
1420
|
extensions: [".vue", ".svelte", ".astro"],
|
|
1396
1421
|
summarize(path14, content) {
|
|
1397
1422
|
let script = "";
|
|
1423
|
+
let usesJsx = path14.toLowerCase().endsWith(".astro");
|
|
1398
1424
|
if (path14.toLowerCase().endsWith(".astro")) {
|
|
1399
1425
|
const frontmatter = ASTRO_FRONTMATTER.exec(content);
|
|
1400
1426
|
if (frontmatter) script += `${frontmatter[1]}
|
|
1401
1427
|
`;
|
|
1402
1428
|
}
|
|
1403
1429
|
for (const match of content.matchAll(SCRIPT_BLOCK)) {
|
|
1404
|
-
|
|
1430
|
+
if (JSX_LANG.test(match[1] ?? "")) usesJsx = true;
|
|
1431
|
+
script += `${match[2]}
|
|
1405
1432
|
`;
|
|
1406
1433
|
}
|
|
1407
1434
|
const name = componentName(path14);
|
|
@@ -1413,7 +1440,7 @@ var sfcProfile = {
|
|
|
1413
1440
|
}
|
|
1414
1441
|
return { summary: finalizeSummary(summary2), quality: "heuristic" };
|
|
1415
1442
|
}
|
|
1416
|
-
const summary = summarizeTypeScriptSource(`${name}
|
|
1443
|
+
const summary = summarizeTypeScriptSource(`${name}.${usesJsx ? "tsx" : "ts"}`, script);
|
|
1417
1444
|
summary.reactComponents.push(name);
|
|
1418
1445
|
summary.exports.push(name);
|
|
1419
1446
|
return { summary: finalizeSummary(summary), quality: "ast" };
|
|
@@ -1847,18 +1874,22 @@ function isBinaryFile(absolutePath) {
|
|
|
1847
1874
|
}
|
|
1848
1875
|
|
|
1849
1876
|
// src/ast/imports.ts
|
|
1877
|
+
var SUMMARY_MAX_SOURCE_BYTES = 2 * 1024 * 1024;
|
|
1850
1878
|
var TS_SOURCE_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
|
|
1851
1879
|
var isTsSource = (relativePath) => {
|
|
1852
1880
|
const lower = relativePath.toLowerCase();
|
|
1853
1881
|
return TS_SOURCE_EXTENSIONS.some((extension) => lower.endsWith(extension));
|
|
1854
1882
|
};
|
|
1855
1883
|
function importsOfText(relativePath, text) {
|
|
1884
|
+
if (Buffer.byteLength(text, "utf8") > SUMMARY_MAX_SOURCE_BYTES) return [];
|
|
1856
1885
|
if (isTsSource(relativePath)) return summarizeTypeScriptSource(relativePath, text).imports;
|
|
1857
1886
|
return summarizeWithProfile(relativePath, text)?.summary.imports ?? [];
|
|
1858
1887
|
}
|
|
1859
1888
|
function importsOfFile(relativePath, absolutePath) {
|
|
1860
1889
|
let buffer;
|
|
1861
1890
|
try {
|
|
1891
|
+
const stats = fs8__namespace.statSync(absolutePath);
|
|
1892
|
+
if (!stats.isFile() || stats.size > SUMMARY_MAX_SOURCE_BYTES) return [];
|
|
1862
1893
|
buffer = fs8__namespace.readFileSync(absolutePath);
|
|
1863
1894
|
} catch {
|
|
1864
1895
|
return [];
|
|
@@ -3103,9 +3134,18 @@ var DEFAULT_SECRET_PATTERNS = [
|
|
|
3103
3134
|
// The unquoted twin for YAML, docker-compose and `.env`: those formats never
|
|
3104
3135
|
// quote their values, so the rules above cannot see them. `valueGroup` keeps
|
|
3105
3136
|
// `POSTGRES_PASSWORD:` in the output.
|
|
3137
|
+
//
|
|
3138
|
+
// This is the one unquoted rule without `NOT_AFTER_QUOTE`, and the lookbehind is a
|
|
3139
|
+
// string-literal guard rather than a precision rule: a credential assignment *inside* a
|
|
3140
|
+
// literal — `const dsn = "password=hunter2;host=db"`, `curl -d "password=hunter2"` — was
|
|
3141
|
+
// rejected before it could be considered, and a DSN is a credential in a string. What made the
|
|
3142
|
+
// lookbehind redundant is the shape of `UNQUOTED_LITERAL`: a value has to start with a word
|
|
3143
|
+
// character, so `["awsSecret:", "apiKey:"]` — the list of key names the lookbehind was added
|
|
3144
|
+
// for — cannot match here anyway. `redact.ts` still refuses a match whose separator is inside
|
|
3145
|
+
// the literal, which is the case that list actually is.
|
|
3106
3146
|
rule: "credential-assignment-unquoted",
|
|
3107
3147
|
pattern: new RegExp(
|
|
3108
|
-
`${
|
|
3148
|
+
`${UNQUOTED_STRONG_NAME}\\s{0,8}${ASSIGN}\\s{0,8}${NOT_A_LITERAL_VALUE}${UNQUOTED_LITERAL}`,
|
|
3109
3149
|
"i"
|
|
3110
3150
|
),
|
|
3111
3151
|
valueGroup: 1
|
|
@@ -3140,6 +3180,27 @@ var DEFAULT_SECRET_PATTERNS = [
|
|
|
3140
3180
|
pattern: /(?<!["'])(?:api[_-]?key|secret[_-]?key|auth[_-]?token|client[_-]?secret|access[_-]?token|refresh[_-]?token|private[_-]?key|password|passwd|pwd)["']?\s*(?<![=!<>])[:=](?!=)\s*["']([^"'\s]{8,256})["']/i,
|
|
3141
3181
|
valueGroup: 1
|
|
3142
3182
|
},
|
|
3183
|
+
{
|
|
3184
|
+
// `${VAR:-fallback}` — a default value in a shell script, a `.env`, docker-compose or a
|
|
3185
|
+
// GitHub Actions workflow.
|
|
3186
|
+
//
|
|
3187
|
+
// This shape defeated every rule above it, and each refusal was individually reasonable:
|
|
3188
|
+
// the quoted rules need a quote after the separator, and the unquoted ones need the value to
|
|
3189
|
+
// begin with a word character — a fallback begins with `$`. So
|
|
3190
|
+
// `POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-MyProdPassword123!}` was emitted whole, `.env` files
|
|
3191
|
+
// and compose files included, which is where that idiom is the norm.
|
|
3192
|
+
//
|
|
3193
|
+
// The **fallback** is what gets masked, not the whole expansion: the variable name is the
|
|
3194
|
+
// readable context, exactly as `POSTGRES_PASSWORD:` is kept by the rule above. A single
|
|
3195
|
+
// interpolation with no operator (`${DB_PASSWORD}`) still does not match — there is nothing
|
|
3196
|
+
// between the braces to mask, and `isTemplateInterpolation` keeps such a value readable.
|
|
3197
|
+
rule: "interpolation-fallback-secret",
|
|
3198
|
+
pattern: new RegExp(
|
|
3199
|
+
`(?:["']${STRONG_CREDENTIAL_NAME}["']|${NOT_AFTER_QUOTE}${STRONG_CREDENTIAL_NAME})\\s{0,8}${ASSIGN}\\s{0,8}["'\`]?\\$\\{[A-Za-z_][A-Za-z0-9_]*:?[-=?+]([^}"'\`\\r\\n]{2,512})\\}["'\`]?`,
|
|
3200
|
+
"i"
|
|
3201
|
+
),
|
|
3202
|
+
valueGroup: 1
|
|
3203
|
+
},
|
|
3143
3204
|
{
|
|
3144
3205
|
// Covers `.env` / shell assignment syntax, which never quotes its values and
|
|
3145
3206
|
// was therefore invisible to the rule above. Anchored to the line start and
|
|
@@ -3167,8 +3228,8 @@ var DEFAULT_SECRET_PATTERNS = [
|
|
|
3167
3228
|
valueGroup: 1
|
|
3168
3229
|
}
|
|
3169
3230
|
];
|
|
3170
|
-
var PEM_BLOCK_PATTERN = /-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----[\s\S]*?-----END (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----/g;
|
|
3171
|
-
var PEM_UNTERMINATED_PATTERN = /-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----(?:\r
|
|
3231
|
+
var PEM_BLOCK_PATTERN = /-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----(?:(?!-----BEGIN)[\s\S])*?-----END (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----/g;
|
|
3232
|
+
var PEM_UNTERMINATED_PATTERN = /-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----(?:\r\n|\n|\r)(?:(?:[ \t]*(?:Proc-Type|DEK-Info|Comment|Version):[^\r\n]*|[ \t]*)(?:\r\n|\n|\r))*(?:[ \t]*[A-Za-z0-9+/=]{8,}[ \t]*(?:\r\n|\n|\r|$))+/g;
|
|
3172
3233
|
|
|
3173
3234
|
// src/security/redact.ts
|
|
3174
3235
|
var REDACTION_MARKER = "[REDACTED: potential secret-like value omitted from snapshot]";
|
|
@@ -3262,6 +3323,20 @@ function toGlobal(rule) {
|
|
|
3262
3323
|
return new RegExp(rule.pattern.source, [...flags].join(""));
|
|
3263
3324
|
}
|
|
3264
3325
|
var LINE_BREAK = /(\r\n|\n|\r)/;
|
|
3326
|
+
var LINE_TERMINATOR = /\r\n|\n|\r/g;
|
|
3327
|
+
var COMPILED_RULES = /* @__PURE__ */ new WeakMap();
|
|
3328
|
+
function compiledRuleFor(rule) {
|
|
3329
|
+
let compiled = COMPILED_RULES.get(rule);
|
|
3330
|
+
if (compiled === void 0) {
|
|
3331
|
+
compiled = {
|
|
3332
|
+
rule: rule.rule,
|
|
3333
|
+
pattern: toGlobal(rule),
|
|
3334
|
+
...rule.valueGroup === void 0 ? {} : { valueGroup: rule.valueGroup }
|
|
3335
|
+
};
|
|
3336
|
+
COMPILED_RULES.set(rule, compiled);
|
|
3337
|
+
}
|
|
3338
|
+
return compiled;
|
|
3339
|
+
}
|
|
3265
3340
|
function scanAndRedactSecrets(content, rules, filePath) {
|
|
3266
3341
|
const findings = [];
|
|
3267
3342
|
let redacted = content;
|
|
@@ -3273,18 +3348,15 @@ function scanAndRedactSecrets(content, rules, filePath) {
|
|
|
3273
3348
|
blockPattern.lastIndex += 1;
|
|
3274
3349
|
continue;
|
|
3275
3350
|
}
|
|
3276
|
-
const
|
|
3277
|
-
const
|
|
3351
|
+
const before = redacted.slice(0, match.index);
|
|
3352
|
+
const line = (before.match(LINE_TERMINATOR) ?? []).length + 1;
|
|
3353
|
+
const newlines = (match[0].match(LINE_TERMINATOR) ?? []).length;
|
|
3278
3354
|
findings.push({ rules: ["private-key-block"], line, path: filePath });
|
|
3279
|
-
redacted =
|
|
3355
|
+
redacted = before + PEM_REDACTION_MARKER + "\n".repeat(newlines) + redacted.slice(match.index + match[0].length);
|
|
3280
3356
|
blockPattern.lastIndex = match.index + PEM_REDACTION_MARKER.length + newlines;
|
|
3281
3357
|
}
|
|
3282
3358
|
}
|
|
3283
|
-
const compiled = rules.map(
|
|
3284
|
-
rule: rule.rule,
|
|
3285
|
-
pattern: toGlobal(rule),
|
|
3286
|
-
...rule.valueGroup === void 0 ? {} : { valueGroup: rule.valueGroup }
|
|
3287
|
-
}));
|
|
3359
|
+
const compiled = rules.map(compiledRuleFor);
|
|
3288
3360
|
const segments = redacted.split(LINE_BREAK);
|
|
3289
3361
|
let lineNumber = 1;
|
|
3290
3362
|
for (let index = 0; index < segments.length; index += 2) {
|
|
@@ -3302,8 +3374,10 @@ function scanAndRedactSecrets(content, rules, filePath) {
|
|
|
3302
3374
|
}
|
|
3303
3375
|
const group = valueGroup === void 0 ? void 0 : match.indices?.[valueGroup];
|
|
3304
3376
|
if (group && isSelfNamingConstant(line, group[0], group[1])) continue;
|
|
3305
|
-
if (valueGroup !== void 0 && startsInsideStringLiteral(line, match.index))
|
|
3306
|
-
|
|
3377
|
+
if (valueGroup !== void 0 && startsInsideStringLiteral(line, match.index, group?.[0])) {
|
|
3378
|
+
continue;
|
|
3379
|
+
}
|
|
3380
|
+
if (group && isUnquotedValue(line, group[0]) && isDeclaredBinding(line, match.index, filePath)) {
|
|
3307
3381
|
continue;
|
|
3308
3382
|
}
|
|
3309
3383
|
if (group && isTemplateInterpolation(line, group[0], group[1])) continue;
|
|
@@ -3336,14 +3410,20 @@ function expandOverToken(line, start, end) {
|
|
|
3336
3410
|
while (right < line.length && TOKEN_CHARS_RIGHT.test(line[right])) right += 1;
|
|
3337
3411
|
return { start: left, end: right };
|
|
3338
3412
|
}
|
|
3339
|
-
function startsInsideStringLiteral(line, matchIndex) {
|
|
3413
|
+
function startsInsideStringLiteral(line, matchIndex, valueStart) {
|
|
3340
3414
|
let runStart = matchIndex;
|
|
3341
3415
|
while (runStart > 0 && /[A-Za-z0-9_-]/.test(line[runStart - 1])) runStart -= 1;
|
|
3342
3416
|
const before = runStart > 0 ? line[runStart - 1] : "";
|
|
3343
|
-
|
|
3417
|
+
if (before !== '"' && before !== "'" && before !== "`") return false;
|
|
3418
|
+
if (valueStart === void 0) return true;
|
|
3419
|
+
return /["'`]/.test(line.slice(matchIndex, valueStart));
|
|
3344
3420
|
}
|
|
3345
3421
|
function isTemplateInterpolation(line, start, end) {
|
|
3346
|
-
|
|
3422
|
+
if (line[start] !== "$" || line[start + 1] !== "{" || line[end - 1] !== "}") {
|
|
3423
|
+
return false;
|
|
3424
|
+
}
|
|
3425
|
+
const inner = line.slice(start + 2, end - 1).trim();
|
|
3426
|
+
return /^[A-Za-z_$][A-Za-z0-9_$.()[\]]*$/.test(inner);
|
|
3347
3427
|
}
|
|
3348
3428
|
function isSelfNamingConstant(line, start, end) {
|
|
3349
3429
|
const value = line.slice(start, end);
|
|
@@ -3368,9 +3448,19 @@ function isUnquotedValue(line, start) {
|
|
|
3368
3448
|
const before = start > 0 ? line[start - 1] : "";
|
|
3369
3449
|
return before !== '"' && before !== "'" && before !== "`";
|
|
3370
3450
|
}
|
|
3371
|
-
var DECLARATION_KEYWORDS = /\b(?:const|let|var|readonly|public|private|protected|static|
|
|
3451
|
+
var DECLARATION_KEYWORDS = /\b(?:const|let|var|readonly|public|private|protected|static|using)\s+$/;
|
|
3452
|
+
var ASSIGNMENT_FILE = /\.(?:sh|bash|zsh|ksh|fish|env|ya?ml|toml|ini|conf|cfg|properties|tf|tfvars|service)$/i;
|
|
3453
|
+
var ASSIGNMENT_BASENAME = /^(?:\.env(?:\.[^/]*)?|\.envrc|\.profile|\.bashrc|\.zshrc|\.bash_profile)$/i;
|
|
3454
|
+
function isAssignmentFile(filePath) {
|
|
3455
|
+
if (filePath === void 0) return false;
|
|
3456
|
+
const normalised = filePath.replace(/\\/g, "/");
|
|
3457
|
+
if (ASSIGNMENT_FILE.test(normalised)) return true;
|
|
3458
|
+
const base = normalised.slice(normalised.lastIndexOf("/") + 1);
|
|
3459
|
+
return ASSIGNMENT_BASENAME.test(base);
|
|
3460
|
+
}
|
|
3372
3461
|
var DECLARATION_WINDOW = 40;
|
|
3373
|
-
function isDeclaredBinding(line, matchIndex) {
|
|
3462
|
+
function isDeclaredBinding(line, matchIndex, filePath) {
|
|
3463
|
+
if (isAssignmentFile(filePath)) return false;
|
|
3374
3464
|
let runStart = matchIndex;
|
|
3375
3465
|
while (runStart > 0 && /[A-Za-z0-9_$]/.test(line[runStart - 1])) runStart -= 1;
|
|
3376
3466
|
const from = Math.max(0, runStart - DECLARATION_WINDOW);
|
|
@@ -3412,6 +3502,15 @@ function readLinkTarget(linkPath, fallback) {
|
|
|
3412
3502
|
return fallback;
|
|
3413
3503
|
}
|
|
3414
3504
|
}
|
|
3505
|
+
function brokenLinkRecord(linkPath, relativePath, rootReal) {
|
|
3506
|
+
const rawTarget = readLinkTarget(linkPath, linkPath);
|
|
3507
|
+
const resolvedFallback = path10__namespace.resolve(path10__namespace.dirname(linkPath), rawTarget);
|
|
3508
|
+
return isInside(rootReal, resolvedFallback) ? { path: relativePath, reason: "read-error", detail: "broken symlink" } : {
|
|
3509
|
+
path: relativePath,
|
|
3510
|
+
reason: "outside-root",
|
|
3511
|
+
detail: `link target resolves outside the scanned root (target: ${rawTarget}); not followed`
|
|
3512
|
+
};
|
|
3513
|
+
}
|
|
3415
3514
|
function isInside(root, candidate) {
|
|
3416
3515
|
const relative8 = path10__namespace.relative(root, candidate);
|
|
3417
3516
|
return relative8 === "" || !relative8.startsWith(`..${path10__namespace.sep}`) && relative8 !== ".." && !path10__namespace.isAbsolute(relative8);
|
|
@@ -3501,6 +3600,13 @@ function isSensitivePath(relativePath) {
|
|
|
3501
3600
|
return matchesSensitiveList(posixPath, base);
|
|
3502
3601
|
}
|
|
3503
3602
|
var GLOBAL_PATTERNS = /* @__PURE__ */ new WeakMap();
|
|
3603
|
+
var GLOB_REGEX_CACHE = /* @__PURE__ */ new Map();
|
|
3604
|
+
var GITIGNORE_REGEX_CACHE = /* @__PURE__ */ new Map();
|
|
3605
|
+
var REGEX_CACHE_LIMIT = 4096;
|
|
3606
|
+
function rememberCompiled(cache, key, value) {
|
|
3607
|
+
if (cache.size >= REGEX_CACHE_LIMIT) cache.clear();
|
|
3608
|
+
cache.set(key, value);
|
|
3609
|
+
}
|
|
3504
3610
|
function globalPattern(pattern) {
|
|
3505
3611
|
let compiled = GLOBAL_PATTERNS.get(pattern);
|
|
3506
3612
|
if (compiled === void 0) {
|
|
@@ -3511,8 +3617,8 @@ function globalPattern(pattern) {
|
|
|
3511
3617
|
}
|
|
3512
3618
|
var DEFAULT_PATH_RULES = [...DEFAULT_SECRET_PATTERNS];
|
|
3513
3619
|
function pathScanRules(extraRules) {
|
|
3514
|
-
if (extraRules === void 0
|
|
3515
|
-
return
|
|
3620
|
+
if (extraRules === void 0) return DEFAULT_PATH_RULES;
|
|
3621
|
+
return extraRules;
|
|
3516
3622
|
}
|
|
3517
3623
|
function findSecretInPath(relativePath, extraRules) {
|
|
3518
3624
|
const posixPath = relativePath.replace(/\\/g, "/");
|
|
@@ -3561,11 +3667,22 @@ function maskSkipPaths(records, extraRules) {
|
|
|
3561
3667
|
});
|
|
3562
3668
|
}
|
|
3563
3669
|
function globToRegExp(glob) {
|
|
3670
|
+
const cached = GLOB_REGEX_CACHE.get(glob);
|
|
3671
|
+
if (cached !== void 0) return cached;
|
|
3564
3672
|
const normalized = glob.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+$/, "");
|
|
3565
3673
|
const anchored = normalized.startsWith("/");
|
|
3566
3674
|
const body = anchored ? normalized.slice(1) : normalized;
|
|
3567
3675
|
const prefix = anchored || body.includes("/") ? "^" : "(?:^|.*/)";
|
|
3568
|
-
|
|
3676
|
+
let compiled;
|
|
3677
|
+
try {
|
|
3678
|
+
compiled = new RegExp(`${prefix}${globBodyToRegExp(body, true)}(?:/.*)?$`);
|
|
3679
|
+
} catch (error) {
|
|
3680
|
+
throw new Error(
|
|
3681
|
+
`"${glob}" is not a valid glob: ${error.message}. A character class must be ascending, as in "[a-z]".`
|
|
3682
|
+
);
|
|
3683
|
+
}
|
|
3684
|
+
rememberCompiled(GLOB_REGEX_CACHE, glob, compiled);
|
|
3685
|
+
return compiled;
|
|
3569
3686
|
}
|
|
3570
3687
|
function globBodyToRegExp(body, allowBraces) {
|
|
3571
3688
|
let out = "";
|
|
@@ -3677,6 +3794,14 @@ function escapeRegExpChar(character) {
|
|
|
3677
3794
|
return /[\\^$.*+?()[\]{}|/]/.test(character) ? `\\${character}` : character;
|
|
3678
3795
|
}
|
|
3679
3796
|
function matchGitignorePattern(target, pattern) {
|
|
3797
|
+
let compiled = GITIGNORE_REGEX_CACHE.get(pattern);
|
|
3798
|
+
if (compiled === void 0) {
|
|
3799
|
+
compiled = compileGitignorePattern(pattern);
|
|
3800
|
+
rememberCompiled(GITIGNORE_REGEX_CACHE, pattern, compiled);
|
|
3801
|
+
}
|
|
3802
|
+
return compiled.test(target);
|
|
3803
|
+
}
|
|
3804
|
+
function compileGitignorePattern(pattern) {
|
|
3680
3805
|
const anchored = pattern.startsWith("/");
|
|
3681
3806
|
const body = anchored ? pattern.slice(1) : pattern;
|
|
3682
3807
|
let source = "";
|
|
@@ -3725,7 +3850,11 @@ function matchGitignorePattern(target, pattern) {
|
|
|
3725
3850
|
source += escapeRegExpChar(character);
|
|
3726
3851
|
}
|
|
3727
3852
|
const prefix = anchored || body.includes("/") ? "^" : "(?:^|.*/)";
|
|
3728
|
-
|
|
3853
|
+
try {
|
|
3854
|
+
return new RegExp(`${prefix}${source}(?:/.*)?$`);
|
|
3855
|
+
} catch {
|
|
3856
|
+
return /$^/;
|
|
3857
|
+
}
|
|
3729
3858
|
}
|
|
3730
3859
|
function matchesGitignoreRule(rule, scoped, isDirectory) {
|
|
3731
3860
|
if (!rule.dirOnly) return matchGitignorePattern(scoped, rule.pattern);
|
|
@@ -3755,14 +3884,31 @@ function gitignoreVerdict(layers, relativePath, isDirectory) {
|
|
|
3755
3884
|
}
|
|
3756
3885
|
return verdict;
|
|
3757
3886
|
}
|
|
3758
|
-
|
|
3887
|
+
var DEFAULT_TOOL_DIR_NAMES = ["snapshot"];
|
|
3888
|
+
function toolDirNamesFor(toolOwnedPaths) {
|
|
3889
|
+
const names = new Set(DEFAULT_TOOL_DIR_NAMES);
|
|
3890
|
+
for (const entry of toolOwnedPaths) {
|
|
3891
|
+
const base = entry.replace(/\\/g, "/").replace(/\/+$/, "").split("/").pop();
|
|
3892
|
+
if (base !== void 0 && base.length > 0) names.add(base);
|
|
3893
|
+
}
|
|
3894
|
+
return [...names];
|
|
3895
|
+
}
|
|
3896
|
+
function isToolLeftoverName(name, dirNames) {
|
|
3897
|
+
for (const dirName of dirNames) {
|
|
3898
|
+
if (name.startsWith(`${dirName}.backup-`) || name.startsWith(`${dirName}.partial-`)) {
|
|
3899
|
+
return true;
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
return false;
|
|
3903
|
+
}
|
|
3904
|
+
function defaultIgnoreReason(relativePath, toolDirNames = DEFAULT_TOOL_DIR_NAMES) {
|
|
3759
3905
|
const posixPath = relativePath.replace(/\\/g, "/");
|
|
3760
3906
|
const parts = posixPath.split("/");
|
|
3761
3907
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
3762
3908
|
if (DEFAULT_IGNORED_DIRS.includes(parts[i])) {
|
|
3763
3909
|
return `built-in ignore: directory "${parts[i]}"`;
|
|
3764
3910
|
}
|
|
3765
|
-
if (parts[i]
|
|
3911
|
+
if (isToolLeftoverName(parts[i], toolDirNames)) {
|
|
3766
3912
|
return `built-in ignore: leftover snapshot backup "${parts[i]}"`;
|
|
3767
3913
|
}
|
|
3768
3914
|
}
|
|
@@ -3770,6 +3916,9 @@ function defaultIgnoreReason(relativePath) {
|
|
|
3770
3916
|
if (DEFAULT_IGNORED_FILES.includes(base)) {
|
|
3771
3917
|
return `built-in ignore: filename "${base}"`;
|
|
3772
3918
|
}
|
|
3919
|
+
if (isToolLeftoverName(base, toolDirNames)) {
|
|
3920
|
+
return `built-in ignore: leftover snapshot backup "${base}"`;
|
|
3921
|
+
}
|
|
3773
3922
|
return null;
|
|
3774
3923
|
}
|
|
3775
3924
|
function listIgnoredPaths(cwd) {
|
|
@@ -3838,41 +3987,72 @@ function dropLinkedDirectories(cwd, candidates, skipped) {
|
|
|
3838
3987
|
}
|
|
3839
3988
|
const reported = /* @__PURE__ */ new Set();
|
|
3840
3989
|
const kept = [];
|
|
3990
|
+
const report = (linkedPath, record) => {
|
|
3991
|
+
if (reported.has(linkedPath)) return;
|
|
3992
|
+
reported.add(linkedPath);
|
|
3993
|
+
skipped.push(record);
|
|
3994
|
+
};
|
|
3841
3995
|
for (const candidate of candidates) {
|
|
3842
3996
|
const parts = candidate.split("/");
|
|
3843
|
-
let
|
|
3997
|
+
let linkedPath = null;
|
|
3844
3998
|
for (let depth = 1; depth <= parts.length; depth += 1) {
|
|
3845
3999
|
const prefix = parts.slice(0, depth).join("/");
|
|
3846
4000
|
if (isLink(path10__namespace.join(cwd, prefix))) {
|
|
3847
|
-
|
|
4001
|
+
linkedPath = prefix;
|
|
3848
4002
|
break;
|
|
3849
4003
|
}
|
|
3850
4004
|
}
|
|
3851
|
-
if (
|
|
4005
|
+
if (linkedPath === null) {
|
|
3852
4006
|
kept.push(candidate);
|
|
3853
4007
|
continue;
|
|
3854
4008
|
}
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
let targetReal = absolute;
|
|
4009
|
+
const absolute = path10__namespace.join(cwd, linkedPath);
|
|
4010
|
+
const rawTarget = readLinkTarget(absolute, absolute);
|
|
4011
|
+
let targetReal = null;
|
|
3859
4012
|
try {
|
|
3860
4013
|
targetReal = fs8__namespace.realpathSync(absolute);
|
|
3861
4014
|
} catch {
|
|
4015
|
+
targetReal = null;
|
|
3862
4016
|
}
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
} : {
|
|
3871
|
-
path: linkedDir,
|
|
4017
|
+
if (targetReal === null) {
|
|
4018
|
+
report(linkedPath, brokenLinkRecord(absolute, linkedPath, rootReal));
|
|
4019
|
+
continue;
|
|
4020
|
+
}
|
|
4021
|
+
if (!isInside(rootReal, targetReal)) {
|
|
4022
|
+
report(linkedPath, {
|
|
4023
|
+
path: linkedPath,
|
|
3872
4024
|
reason: "outside-root",
|
|
3873
|
-
detail: `link target resolves outside the scanned root (target: ${
|
|
3874
|
-
}
|
|
3875
|
-
|
|
4025
|
+
detail: `link target resolves outside the scanned root (target: ${rawTarget}); not followed`
|
|
4026
|
+
});
|
|
4027
|
+
continue;
|
|
4028
|
+
}
|
|
4029
|
+
let stats = null;
|
|
4030
|
+
try {
|
|
4031
|
+
stats = fs8__namespace.statSync(absolute);
|
|
4032
|
+
} catch {
|
|
4033
|
+
stats = null;
|
|
4034
|
+
}
|
|
4035
|
+
if (stats === null) {
|
|
4036
|
+
report(linkedPath, { path: linkedPath, reason: "read-error", detail: "unreadable symlink" });
|
|
4037
|
+
continue;
|
|
4038
|
+
}
|
|
4039
|
+
if (linkedPath !== candidate || stats.isDirectory()) {
|
|
4040
|
+
report(linkedPath, {
|
|
4041
|
+
path: linkedPath,
|
|
4042
|
+
reason: "symlink",
|
|
4043
|
+
detail: `directory link not followed (target: ${rawTarget})`
|
|
4044
|
+
});
|
|
4045
|
+
continue;
|
|
4046
|
+
}
|
|
4047
|
+
if (!stats.isFile()) {
|
|
4048
|
+
report(linkedPath, {
|
|
4049
|
+
path: linkedPath,
|
|
4050
|
+
reason: "symlink",
|
|
4051
|
+
detail: `link to neither a file nor a directory (target: ${rawTarget})`
|
|
4052
|
+
});
|
|
4053
|
+
continue;
|
|
4054
|
+
}
|
|
4055
|
+
kept.push(candidate);
|
|
3876
4056
|
}
|
|
3877
4057
|
return kept;
|
|
3878
4058
|
}
|
|
@@ -3919,6 +4099,7 @@ function collectFiles(cwd, options = {}) {
|
|
|
3919
4099
|
(options.toolOwnedPaths ?? []).map((entry) => entry.replace(/\\/g, "/"))
|
|
3920
4100
|
);
|
|
3921
4101
|
const isToolOwned = makeToolOwnedDecider(cwd, [...toolOwnedPaths]);
|
|
4102
|
+
const toolDirNames = toolDirNamesFor(toolOwnedPaths);
|
|
3922
4103
|
let candidates;
|
|
3923
4104
|
const skipped = [];
|
|
3924
4105
|
const discovery = options.discovery ?? "auto";
|
|
@@ -3947,7 +4128,7 @@ function collectFiles(cwd, options = {}) {
|
|
|
3947
4128
|
}
|
|
3948
4129
|
const files = candidates.filter((file) => {
|
|
3949
4130
|
if (isToolOwned(file)) return false;
|
|
3950
|
-
const ignored = defaultIgnoreReason(file);
|
|
4131
|
+
const ignored = defaultIgnoreReason(file, toolDirNames);
|
|
3951
4132
|
if (ignored) {
|
|
3952
4133
|
skipped.push({ path: file, reason: "default-ignore", detail: ignored });
|
|
3953
4134
|
return false;
|
|
@@ -4002,6 +4183,7 @@ function rootRealFor(root) {
|
|
|
4002
4183
|
function walkDirectory(dir, baseDir, rootReal, visited, reservedPaths = /* @__PURE__ */ new Set(), parentGitignoreLayers = []) {
|
|
4003
4184
|
const results = { files: [], skipped: [] };
|
|
4004
4185
|
const stack = [];
|
|
4186
|
+
const toolDirNames = toolDirNamesFor(reservedPaths);
|
|
4005
4187
|
const relativeToBase = (target) => path10__namespace.relative(baseDir, target).replace(/\\/g, "/") || ".";
|
|
4006
4188
|
const enter = (current, layers) => {
|
|
4007
4189
|
if (visited.has(current)) return false;
|
|
@@ -4046,11 +4228,11 @@ function walkDirectory(dir, baseDir, rootReal, visited, reservedPaths = /* @__PU
|
|
|
4046
4228
|
});
|
|
4047
4229
|
continue;
|
|
4048
4230
|
}
|
|
4049
|
-
if (DEFAULT_IGNORED_FILES.includes(entry.name) || entry.name
|
|
4231
|
+
if (DEFAULT_IGNORED_FILES.includes(entry.name) || isToolLeftoverName(entry.name, toolDirNames)) {
|
|
4050
4232
|
results.skipped.push({
|
|
4051
4233
|
path: relPath,
|
|
4052
4234
|
reason: "default-ignore",
|
|
4053
|
-
detail: "built-in ignore: filename"
|
|
4235
|
+
detail: isToolLeftoverName(entry.name, toolDirNames) ? `built-in ignore: leftover snapshot backup "${entry.name}" (not descended)` : "built-in ignore: filename"
|
|
4054
4236
|
});
|
|
4055
4237
|
continue;
|
|
4056
4238
|
}
|
|
@@ -4071,7 +4253,7 @@ function walkDirectory(dir, baseDir, rootReal, visited, reservedPaths = /* @__PU
|
|
|
4071
4253
|
try {
|
|
4072
4254
|
targetReal = fs8__namespace.realpathSync(fullPath);
|
|
4073
4255
|
} catch {
|
|
4074
|
-
results.skipped.push(
|
|
4256
|
+
results.skipped.push(brokenLinkRecord(fullPath, relPath, rootReal));
|
|
4075
4257
|
continue;
|
|
4076
4258
|
}
|
|
4077
4259
|
let stats;
|
|
@@ -4196,15 +4378,19 @@ function normalizeBudgets(budgets, maxPartBytes) {
|
|
|
4196
4378
|
}
|
|
4197
4379
|
function normalizeResolvedConfig(config) {
|
|
4198
4380
|
const discovery = isDiscoveryMode(config.discovery) ? config.discovery : "auto";
|
|
4381
|
+
const monolithWanted = config.includeMonolith === true || config.artifacts?.monolith === true;
|
|
4382
|
+
const artifacts = resolveArtifacts(
|
|
4383
|
+
config.artifacts,
|
|
4384
|
+
void 0,
|
|
4385
|
+
monolithWanted,
|
|
4386
|
+
monolithWanted
|
|
4387
|
+
);
|
|
4199
4388
|
return markResolvedConfig({
|
|
4200
4389
|
...config,
|
|
4201
4390
|
discovery,
|
|
4391
|
+
includeMonolith: artifacts.monolith,
|
|
4202
4392
|
secretRules: compileSecretRules(config.secretRules),
|
|
4203
|
-
artifacts
|
|
4204
|
-
config.artifacts,
|
|
4205
|
-
void 0,
|
|
4206
|
-
config.includeMonolith === true
|
|
4207
|
-
),
|
|
4393
|
+
artifacts,
|
|
4208
4394
|
include: resolveInclude(config.include),
|
|
4209
4395
|
preset: typeof config.preset === "string" ? config.preset : "generic",
|
|
4210
4396
|
presetExclude: [
|
|
@@ -4413,6 +4599,16 @@ async function importConfigModule(fullPath) {
|
|
|
4413
4599
|
url$1.searchParams.set("codebaseSnapshotLoad", String(moduleConfigLoadToken));
|
|
4414
4600
|
return await import(url$1.href);
|
|
4415
4601
|
}
|
|
4602
|
+
function attachConfigDir(config, filePath) {
|
|
4603
|
+
if (typeof config === "object" && config !== null) {
|
|
4604
|
+
Object.defineProperty(config, CONFIG_DIR_SYMBOL, {
|
|
4605
|
+
value: path10__namespace.dirname(filePath),
|
|
4606
|
+
enumerable: false,
|
|
4607
|
+
configurable: true
|
|
4608
|
+
});
|
|
4609
|
+
}
|
|
4610
|
+
return config;
|
|
4611
|
+
}
|
|
4416
4612
|
async function loadConfigFileDetailed(cwd) {
|
|
4417
4613
|
const warnings = [];
|
|
4418
4614
|
const errors = [];
|
|
@@ -4428,7 +4624,7 @@ async function loadConfigFileDetailed(cwd) {
|
|
|
4428
4624
|
);
|
|
4429
4625
|
}
|
|
4430
4626
|
assertKnownConfigKeys(config, fullPath);
|
|
4431
|
-
return { config, file: fullPath, warnings, errors };
|
|
4627
|
+
return { config: attachConfigDir(config, fullPath), file: fullPath, warnings, errors };
|
|
4432
4628
|
} catch (err) {
|
|
4433
4629
|
const raw = err.message;
|
|
4434
4630
|
const message = raw.includes(fullPath) ? raw : `${fullPath}: ${raw}`;
|
|
@@ -4447,7 +4643,7 @@ async function loadConfigFileDetailed(cwd) {
|
|
|
4447
4643
|
const imported = await importConfigModule(fullPath);
|
|
4448
4644
|
const hasDefault = Object.prototype.hasOwnProperty.call(imported, "default");
|
|
4449
4645
|
const config = readConfigExport(hasDefault ? imported.default : imported, fullPath);
|
|
4450
|
-
return { config, file: fullPath, warnings, errors };
|
|
4646
|
+
return { config: attachConfigDir(config, fullPath), file: fullPath, warnings, errors };
|
|
4451
4647
|
} catch (err) {
|
|
4452
4648
|
const message = `Could not load ${fullPath}: ${err.message}`;
|
|
4453
4649
|
warnings.push(message);
|
|
@@ -4465,7 +4661,12 @@ async function loadConfigFileDetailed(cwd) {
|
|
|
4465
4661
|
snapshotKey,
|
|
4466
4662
|
`${pkgJsonPath} (the "snapshot" key)`
|
|
4467
4663
|
);
|
|
4468
|
-
return {
|
|
4664
|
+
return {
|
|
4665
|
+
config: attachConfigDir(snapshotKey, pkgJsonPath),
|
|
4666
|
+
file: pkgJsonPath,
|
|
4667
|
+
warnings,
|
|
4668
|
+
errors
|
|
4669
|
+
};
|
|
4469
4670
|
}
|
|
4470
4671
|
if (snapshotKey !== void 0) {
|
|
4471
4672
|
const kind = Array.isArray(snapshotKey) ? "array" : typeof snapshotKey;
|
|
@@ -4504,7 +4705,7 @@ var DEFAULT_ARTIFACTS = {
|
|
|
4504
4705
|
function isArtifactName(value) {
|
|
4505
4706
|
return ARTIFACT_NAMES.includes(value);
|
|
4506
4707
|
}
|
|
4507
|
-
function resolveArtifacts(requested, skipped, includeMonolith, monolithOverride) {
|
|
4708
|
+
function resolveArtifacts(requested, skipped, includeMonolith, monolithOverride, only) {
|
|
4508
4709
|
const artifacts = {
|
|
4509
4710
|
...DEFAULT_ARTIFACTS,
|
|
4510
4711
|
// `includeMonolith` predates this selection and stays the switch for it.
|
|
@@ -4529,6 +4730,21 @@ function resolveArtifacts(requested, skipped, includeMonolith, monolithOverride)
|
|
|
4529
4730
|
if (monolithOverride !== void 0) {
|
|
4530
4731
|
artifacts.monolith = monolithOverride;
|
|
4531
4732
|
}
|
|
4733
|
+
if (only !== void 0 && only.length > 0) {
|
|
4734
|
+
const keep = /* @__PURE__ */ new Set();
|
|
4735
|
+
for (const name of only) {
|
|
4736
|
+
if (!isArtifactName(name)) {
|
|
4737
|
+
throw new Error(
|
|
4738
|
+
`Unknown artifact "${name}". Expected one of: ${ARTIFACT_NAMES.join(", ")}.`
|
|
4739
|
+
);
|
|
4740
|
+
}
|
|
4741
|
+
keep.add(name);
|
|
4742
|
+
}
|
|
4743
|
+
for (const name of ARTIFACT_NAMES) {
|
|
4744
|
+
artifacts[name] = keep.has(name);
|
|
4745
|
+
}
|
|
4746
|
+
return artifacts;
|
|
4747
|
+
}
|
|
4532
4748
|
for (const name of skipped ?? []) {
|
|
4533
4749
|
if (!isArtifactName(name)) {
|
|
4534
4750
|
throw new Error(
|
|
@@ -4829,7 +5045,8 @@ function resolveConfig(userConfig, cliOptions, baseDir) {
|
|
|
4829
5045
|
userConfig?.artifacts,
|
|
4830
5046
|
cliOptions?.skipArtifacts,
|
|
4831
5047
|
includeMonolith,
|
|
4832
|
-
cliMonolith
|
|
5048
|
+
cliMonolith,
|
|
5049
|
+
cliOptions?.onlyArtifacts
|
|
4833
5050
|
);
|
|
4834
5051
|
const explicitMaxPartBytes = cliOptions?.maxPartBytes ?? userConfig?.maxPartBytes;
|
|
4835
5052
|
const maxPartBytes = boundedBytes(
|
|
@@ -5003,7 +5220,18 @@ function configDigest(config) {
|
|
|
5003
5220
|
excludePatterns: config.excludePatterns,
|
|
5004
5221
|
preset: config.preset,
|
|
5005
5222
|
layersMode: config.layersMode,
|
|
5006
|
-
budgets
|
|
5223
|
+
// `budgets.byLayer` is a plain object, and `JSON.stringify` preserves insertion order — so
|
|
5224
|
+
// `{ docs, api }` and `{ api, docs }` hashed differently despite being the same settings, and
|
|
5225
|
+
// `validate` reported configuration drift for a snapshot nobody had changed. The keys are
|
|
5226
|
+
// canonicalised here; nothing else about the object is order-dependent.
|
|
5227
|
+
budgets: {
|
|
5228
|
+
default: config.budgets.default,
|
|
5229
|
+
byLayer: Object.fromEntries(
|
|
5230
|
+
Object.entries(config.budgets.byLayer).sort(
|
|
5231
|
+
([left], [right]) => left < right ? -1 : left > right ? 1 : 0
|
|
5232
|
+
)
|
|
5233
|
+
)
|
|
5234
|
+
},
|
|
5007
5235
|
// The matcher is what makes a layer a layer. Hashing only the names meant that
|
|
5008
5236
|
// moving `{ name: "api", match: "src/api/**" }` to `"src/v2/**"` produced the same
|
|
5009
5237
|
// digest, so `validate` reported "valid and up to date" for a snapshot whose files
|
|
@@ -5022,9 +5250,21 @@ function configDigest(config) {
|
|
|
5022
5250
|
}
|
|
5023
5251
|
|
|
5024
5252
|
// src/partitioner/preview.ts
|
|
5253
|
+
var LINE_ENDINGS = /\r\n|\r/g;
|
|
5254
|
+
var normaliseLineEndings = (content) => content.replace(LINE_ENDINGS, "\n");
|
|
5025
5255
|
function countLines(content) {
|
|
5026
5256
|
if (content.length === 0) return 0;
|
|
5027
|
-
|
|
5257
|
+
let breaks = 0;
|
|
5258
|
+
for (let index = 0; index < content.length; index += 1) {
|
|
5259
|
+
const code = content.charCodeAt(index);
|
|
5260
|
+
if (code === 10) {
|
|
5261
|
+
breaks += 1;
|
|
5262
|
+
continue;
|
|
5263
|
+
}
|
|
5264
|
+
if (code === 13 && content.charCodeAt(index + 1) !== 10) breaks += 1;
|
|
5265
|
+
}
|
|
5266
|
+
const last = content.charCodeAt(content.length - 1);
|
|
5267
|
+
return last === 10 || last === 13 ? breaks : breaks + 1;
|
|
5028
5268
|
}
|
|
5029
5269
|
function truncateToBytes(content, maxBytes) {
|
|
5030
5270
|
if (maxBytes <= 0) return { content: "", isTruncated: content.length > 0 };
|
|
@@ -5035,17 +5275,18 @@ function truncateToBytes(content, maxBytes) {
|
|
|
5035
5275
|
return { content: slice, isTruncated: true };
|
|
5036
5276
|
}
|
|
5037
5277
|
function truncatePreview(content, headLines, tailLines) {
|
|
5038
|
-
const
|
|
5039
|
-
const
|
|
5278
|
+
const normalised = normaliseLineEndings(content);
|
|
5279
|
+
const lines = normalised.split("\n");
|
|
5280
|
+
const total = countLines(normalised);
|
|
5040
5281
|
if (total <= headLines + tailLines) {
|
|
5041
5282
|
return {
|
|
5042
|
-
content,
|
|
5283
|
+
content: normalised,
|
|
5043
5284
|
isTruncated: false,
|
|
5044
5285
|
originalLines: total,
|
|
5045
5286
|
includedLines: total
|
|
5046
5287
|
};
|
|
5047
5288
|
}
|
|
5048
|
-
const window =
|
|
5289
|
+
const window = normalised.endsWith("\n") ? lines.slice(0, -1) : lines;
|
|
5049
5290
|
const head = window.slice(0, headLines);
|
|
5050
5291
|
const tail = tailLines > 0 ? window.slice(window.length - tailLines) : [];
|
|
5051
5292
|
const omitted = total - head.length - tail.length;
|
|
@@ -5148,6 +5389,10 @@ var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
5148
5389
|
".mjs",
|
|
5149
5390
|
".cjs"
|
|
5150
5391
|
]);
|
|
5392
|
+
var PYTHON_EXTENSIONS = /* @__PURE__ */ new Set([".py", ".pyi"]);
|
|
5393
|
+
var RUBY_EXTENSIONS = /* @__PURE__ */ new Set([".rb", ".rake", ".gemspec"]);
|
|
5394
|
+
var C_EXTENSIONS = /* @__PURE__ */ new Set([".c", ".h", ".cc", ".cpp", ".cxx", ".hpp", ".hxx", ".m", ".mm"]);
|
|
5395
|
+
var PYTHON_SUFFIXES = [".py", ".pyi", "/__init__.py", "/__init__.pyi"];
|
|
5151
5396
|
function buildImportResolver(files) {
|
|
5152
5397
|
const byPath = /* @__PURE__ */ new Map();
|
|
5153
5398
|
const byPathFolded = /* @__PURE__ */ new Map();
|
|
@@ -5174,11 +5419,45 @@ function buildImportResolver(files) {
|
|
|
5174
5419
|
return { byPath, byPathFolded, byStem, byStemFolded };
|
|
5175
5420
|
}
|
|
5176
5421
|
function resolveSpecifier(fromFile, specifier, resolver) {
|
|
5422
|
+
const extension = path10__namespace.posix.extname(fromFile).toLowerCase();
|
|
5423
|
+
const exact = (key) => resolver.byPath.get(key) ?? resolver.byPathFolded.get(key.toLowerCase()) ?? null;
|
|
5424
|
+
const firstOf = (candidates) => {
|
|
5425
|
+
for (const candidate of candidates) {
|
|
5426
|
+
const hit = exact(candidate);
|
|
5427
|
+
if (hit) return hit;
|
|
5428
|
+
}
|
|
5429
|
+
return null;
|
|
5430
|
+
};
|
|
5431
|
+
if (PYTHON_EXTENSIONS.has(extension) && specifier.startsWith(".")) {
|
|
5432
|
+
const dots = /^\.+/.exec(specifier)?.[0].length ?? 0;
|
|
5433
|
+
const rest = specifier.slice(dots).replace(/\./g, "/");
|
|
5434
|
+
let base = path10__namespace.posix.dirname(fromFile);
|
|
5435
|
+
for (let up = 1; up < dots; up += 1) base = path10__namespace.posix.dirname(base);
|
|
5436
|
+
const joined2 = rest ? path10__namespace.posix.normalize(path10__namespace.posix.join(base, rest)) : base;
|
|
5437
|
+
return firstOf([joined2, ...PYTHON_SUFFIXES.map((suffix) => `${joined2}${suffix}`)]);
|
|
5438
|
+
}
|
|
5439
|
+
if (RUBY_EXTENSIONS.has(extension) && specifier.startsWith("./")) {
|
|
5440
|
+
const joined2 = path10__namespace.posix.normalize(
|
|
5441
|
+
path10__namespace.posix.join(path10__namespace.posix.dirname(fromFile), specifier)
|
|
5442
|
+
);
|
|
5443
|
+
return firstOf([`${joined2}.rb`, joined2]);
|
|
5444
|
+
}
|
|
5445
|
+
if (C_EXTENSIONS.has(extension) && specifier.startsWith("./")) {
|
|
5446
|
+
const joined2 = path10__namespace.posix.normalize(
|
|
5447
|
+
path10__namespace.posix.join(path10__namespace.posix.dirname(fromFile), specifier)
|
|
5448
|
+
);
|
|
5449
|
+
return exact(joined2);
|
|
5450
|
+
}
|
|
5451
|
+
if (extension === ".dart" && !specifier.includes(":")) {
|
|
5452
|
+
const joined2 = path10__namespace.posix.normalize(
|
|
5453
|
+
path10__namespace.posix.join(path10__namespace.posix.dirname(fromFile), specifier)
|
|
5454
|
+
);
|
|
5455
|
+
return firstOf([joined2, `${joined2}.dart`]);
|
|
5456
|
+
}
|
|
5177
5457
|
if (!RELATIVE_SPECIFIER.test(specifier)) return null;
|
|
5178
5458
|
const joined = path10__namespace.posix.normalize(
|
|
5179
5459
|
path10__namespace.posix.join(path10__namespace.posix.dirname(fromFile), specifier)
|
|
5180
5460
|
);
|
|
5181
|
-
const exact = (key) => resolver.byPath.get(key) ?? resolver.byPathFolded.get(key.toLowerCase()) ?? null;
|
|
5182
5461
|
const direct = exact(joined);
|
|
5183
5462
|
if (direct) return direct;
|
|
5184
5463
|
for (const suffix of IMPORT_CANDIDATE_SUFFIXES) {
|
|
@@ -5289,10 +5568,13 @@ function describeMatcher(matcher) {
|
|
|
5289
5568
|
return String(matcher);
|
|
5290
5569
|
}
|
|
5291
5570
|
function normalizeTarget(cwd, target) {
|
|
5292
|
-
const
|
|
5293
|
-
const
|
|
5294
|
-
|
|
5295
|
-
|
|
5571
|
+
const resolvedCwd = path10__namespace.resolve(cwd);
|
|
5572
|
+
const absolute = path10__namespace.resolve(resolvedCwd, target);
|
|
5573
|
+
const relative8 = path10__namespace.relative(resolvedCwd, absolute);
|
|
5574
|
+
if (relative8 === "" || relative8 === ".." || relative8.startsWith(`..${path10__namespace.sep}`) || path10__namespace.isAbsolute(relative8)) {
|
|
5575
|
+
return { relative: target.replace(/\\/g, "/"), outsideRoot: true };
|
|
5576
|
+
}
|
|
5577
|
+
return { relative: relative8.split(path10__namespace.sep).join("/"), outsideRoot: false };
|
|
5296
5578
|
}
|
|
5297
5579
|
function findRuleMatch(rules, relativePath) {
|
|
5298
5580
|
return rules.find(
|
|
@@ -5319,9 +5601,19 @@ function readManifest2(config) {
|
|
|
5319
5601
|
}
|
|
5320
5602
|
}
|
|
5321
5603
|
function explainPath(config, target) {
|
|
5322
|
-
const
|
|
5323
|
-
const
|
|
5604
|
+
const normalized = normalizeTarget(config.cwd, target);
|
|
5605
|
+
const relative8 = normalized.relative;
|
|
5324
5606
|
const maskedPath2 = findSecretInPath(relative8, config.secretRules)?.masked ?? relative8;
|
|
5607
|
+
if (normalized.outsideRoot) {
|
|
5608
|
+
return {
|
|
5609
|
+
path: maskedPath2,
|
|
5610
|
+
exists: false,
|
|
5611
|
+
included: false,
|
|
5612
|
+
reason: "outside-root",
|
|
5613
|
+
detail: "path resolves outside the configured repository root and was not inspected"
|
|
5614
|
+
};
|
|
5615
|
+
}
|
|
5616
|
+
const absolute = path10__namespace.join(config.cwd, relative8);
|
|
5325
5617
|
const result = {
|
|
5326
5618
|
path: maskedPath2,
|
|
5327
5619
|
exists: fs8__namespace.existsSync(absolute),
|
|
@@ -5471,41 +5763,62 @@ function renderExplainText(result) {
|
|
|
5471
5763
|
);
|
|
5472
5764
|
return lines.join("\n");
|
|
5473
5765
|
}
|
|
5766
|
+
new async_hooks.AsyncLocalStorage();
|
|
5767
|
+
new async_hooks.AsyncLocalStorage();
|
|
5474
5768
|
|
|
5475
5769
|
// src/ast/structured.ts
|
|
5476
5770
|
function stripJsonComments2(content) {
|
|
5477
5771
|
const text = content.replace(/^\uFEFF/, "");
|
|
5772
|
+
const withoutComments = stripComments(text);
|
|
5773
|
+
return stripTrailingCommas2(withoutComments);
|
|
5774
|
+
}
|
|
5775
|
+
function stripComments(text) {
|
|
5478
5776
|
let out = "";
|
|
5479
5777
|
let inString = false;
|
|
5480
|
-
let
|
|
5481
|
-
let
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
if (char === "
|
|
5487
|
-
|
|
5488
|
-
out += char;
|
|
5489
|
-
}
|
|
5778
|
+
let escaped = false;
|
|
5779
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
5780
|
+
const char = text[index];
|
|
5781
|
+
if (inString) {
|
|
5782
|
+
out += char;
|
|
5783
|
+
if (escaped) escaped = false;
|
|
5784
|
+
else if (char === "\\") escaped = true;
|
|
5785
|
+
else if (char === '"') inString = false;
|
|
5490
5786
|
continue;
|
|
5491
5787
|
}
|
|
5492
|
-
if (
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5788
|
+
if (char === '"') {
|
|
5789
|
+
inString = true;
|
|
5790
|
+
out += char;
|
|
5791
|
+
continue;
|
|
5792
|
+
}
|
|
5793
|
+
if (char === "/" && text[index + 1] === "/") {
|
|
5794
|
+
while (index < text.length && text[index] !== "\n" && text[index] !== "\r") index += 1;
|
|
5795
|
+
index -= 1;
|
|
5796
|
+
continue;
|
|
5797
|
+
}
|
|
5798
|
+
if (char === "/" && text[index + 1] === "*") {
|
|
5799
|
+
index += 2;
|
|
5800
|
+
while (index < text.length && !(text[index] === "*" && text[index + 1] === "/")) {
|
|
5801
|
+
if (text[index] === "\n" || text[index] === "\r") out += text[index];
|
|
5802
|
+
index += 1;
|
|
5496
5803
|
}
|
|
5804
|
+
index += 1;
|
|
5497
5805
|
continue;
|
|
5498
5806
|
}
|
|
5807
|
+
out += char;
|
|
5808
|
+
}
|
|
5809
|
+
return out;
|
|
5810
|
+
}
|
|
5811
|
+
function stripTrailingCommas2(text) {
|
|
5812
|
+
let out = "";
|
|
5813
|
+
let inString = false;
|
|
5814
|
+
let escaped = false;
|
|
5815
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
5816
|
+
const char = text[index];
|
|
5499
5817
|
if (inString) {
|
|
5500
5818
|
out += char;
|
|
5501
|
-
if (
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
i += 1;
|
|
5505
|
-
}
|
|
5506
|
-
} else if (char === '"') {
|
|
5507
|
-
inString = false;
|
|
5508
|
-
}
|
|
5819
|
+
if (escaped) escaped = false;
|
|
5820
|
+
else if (char === "\\") escaped = true;
|
|
5821
|
+
else if (char === '"') inString = false;
|
|
5509
5822
|
continue;
|
|
5510
5823
|
}
|
|
5511
5824
|
if (char === '"') {
|
|
@@ -5513,15 +5826,10 @@ function stripJsonComments2(content) {
|
|
|
5513
5826
|
out += char;
|
|
5514
5827
|
continue;
|
|
5515
5828
|
}
|
|
5516
|
-
if (char === "
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
continue;
|
|
5520
|
-
}
|
|
5521
|
-
if (char === "/" && next === "*") {
|
|
5522
|
-
inBlockComment = true;
|
|
5523
|
-
i += 1;
|
|
5524
|
-
continue;
|
|
5829
|
+
if (char === ",") {
|
|
5830
|
+
let next = index + 1;
|
|
5831
|
+
while (next < text.length && /\s/.test(text[next])) next += 1;
|
|
5832
|
+
if (text[next] === "}" || text[next] === "]") continue;
|
|
5525
5833
|
}
|
|
5526
5834
|
out += char;
|
|
5527
5835
|
}
|
|
@@ -5564,31 +5872,45 @@ function summarizeJson(content) {
|
|
|
5564
5872
|
};
|
|
5565
5873
|
}
|
|
5566
5874
|
}
|
|
5875
|
+
function frontMatterEnd(lines) {
|
|
5876
|
+
if (lines.length < 3 || lines[0].trim() !== "---") return 0;
|
|
5877
|
+
for (let index = 1; index < lines.length; index += 1) {
|
|
5878
|
+
const line = lines[index];
|
|
5879
|
+
const candidate = line.trim();
|
|
5880
|
+
if (candidate === "---" || candidate === "...") {
|
|
5881
|
+
return index > 1 ? index : 0;
|
|
5882
|
+
}
|
|
5883
|
+
if (candidate === "") continue;
|
|
5884
|
+
if (/^#(\s|$)/.test(candidate)) continue;
|
|
5885
|
+
if (/^(`{3,}|~{3,})/.test(candidate)) return 0;
|
|
5886
|
+
if (/^#{1,6}\s+\S/.test(candidate)) return 0;
|
|
5887
|
+
const isYamlMapping = /^[A-Za-z0-9_.-]+\s*:(\s|$)/.test(candidate);
|
|
5888
|
+
const isListItem = /^-(?:(\s|$))/.test(candidate);
|
|
5889
|
+
const isIndented = /^[ \t]/.test(line);
|
|
5890
|
+
if (!isYamlMapping && !isListItem && !isIndented) return 0;
|
|
5891
|
+
}
|
|
5892
|
+
return 0;
|
|
5893
|
+
}
|
|
5567
5894
|
function summarizeMarkdown(content) {
|
|
5568
5895
|
const headings = [];
|
|
5569
5896
|
const frontmatterKeys = [];
|
|
5570
|
-
const lines = content.replace(/^\uFEFF/, "").split(
|
|
5897
|
+
const lines = content.replace(/^\uFEFF/, "").split(/\r\n|\n|\r/);
|
|
5571
5898
|
let inFrontmatter = false;
|
|
5572
5899
|
let fence = null;
|
|
5573
|
-
|
|
5574
|
-
for (let index = 1; index < lines.length; index++) {
|
|
5575
|
-
if (lines[index].trim() === "---") {
|
|
5576
|
-
closesFrontmatter = true;
|
|
5577
|
-
break;
|
|
5578
|
-
}
|
|
5579
|
-
}
|
|
5900
|
+
const frontMatterEndLine = frontMatterEnd(lines);
|
|
5580
5901
|
for (let index = 0; index < lines.length; index++) {
|
|
5581
5902
|
const line = lines[index];
|
|
5582
|
-
if (index === 0 &&
|
|
5903
|
+
if (index === 0 && frontMatterEndLine > 0) {
|
|
5583
5904
|
inFrontmatter = true;
|
|
5584
5905
|
continue;
|
|
5585
5906
|
}
|
|
5586
5907
|
if (inFrontmatter) {
|
|
5587
|
-
|
|
5908
|
+
const trimmedFrontmatter = line.trim();
|
|
5909
|
+
if (trimmedFrontmatter === "---" || trimmedFrontmatter === "...") {
|
|
5588
5910
|
inFrontmatter = false;
|
|
5589
5911
|
continue;
|
|
5590
5912
|
}
|
|
5591
|
-
const match = /^([
|
|
5913
|
+
const match = /^([A-Za-z0-9_.-]+)\s*:/.exec(line);
|
|
5592
5914
|
if (match) frontmatterKeys.push(match[1]);
|
|
5593
5915
|
continue;
|
|
5594
5916
|
}
|
|
@@ -5620,25 +5942,36 @@ function hasCollapsibleBody(node) {
|
|
|
5620
5942
|
const body = node.body;
|
|
5621
5943
|
return body !== void 0 && ts__default.default.isBlock(body);
|
|
5622
5944
|
}
|
|
5623
|
-
function
|
|
5624
|
-
|
|
5945
|
+
function scriptKindFor(fileName) {
|
|
5946
|
+
const lower = fileName.toLowerCase();
|
|
5947
|
+
if (lower.endsWith(".tsx")) return ts__default.default.ScriptKind.TSX;
|
|
5948
|
+
if (lower.endsWith(".jsx")) return ts__default.default.ScriptKind.JSX;
|
|
5949
|
+
if (lower.endsWith(".js") || lower.endsWith(".mjs") || lower.endsWith(".cjs")) {
|
|
5950
|
+
return ts__default.default.ScriptKind.JS;
|
|
5951
|
+
}
|
|
5952
|
+
return ts__default.default.ScriptKind.TS;
|
|
5625
5953
|
}
|
|
5626
5954
|
function skeletonizeTypeScript(source, fileName = "file.ts") {
|
|
5627
|
-
const scriptKind = isTsxFileName(fileName) ? ts__default.default.ScriptKind.TSX : ts__default.default.ScriptKind.TS;
|
|
5628
5955
|
const sourceFile = ts__default.default.createSourceFile(
|
|
5629
5956
|
fileName,
|
|
5630
5957
|
source,
|
|
5631
5958
|
ts__default.default.ScriptTarget.Latest,
|
|
5632
|
-
|
|
5633
|
-
|
|
5959
|
+
// `setParentNodes: false`. Nothing here reads `.parent` — the one `getStart` call is given the
|
|
5960
|
+
// source file explicitly, which is the reason that argument exists. Asking for parent pointers
|
|
5961
|
+
// makes the parser run a second full pass over every node in the file to set them, on top of
|
|
5962
|
+
// the summary parse this same file already pays for.
|
|
5963
|
+
false,
|
|
5964
|
+
scriptKindFor(fileName)
|
|
5634
5965
|
);
|
|
5635
5966
|
const spans = [];
|
|
5636
5967
|
const visit = (node) => {
|
|
5637
5968
|
if ((ts__default.default.isFunctionDeclaration(node) || ts__default.default.isMethodDeclaration(node) || ts__default.default.isConstructorDeclaration(node) || ts__default.default.isGetAccessorDeclaration(node) || ts__default.default.isSetAccessorDeclaration(node) || ts__default.default.isFunctionExpression(node) || ts__default.default.isArrowFunction(node)) && hasCollapsibleBody(node)) {
|
|
5638
5969
|
const body = node.body;
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5970
|
+
if (body.statements.length > 0) {
|
|
5971
|
+
const start = body.getStart(sourceFile);
|
|
5972
|
+
const end = body.getEnd();
|
|
5973
|
+
if (end > start) spans.push({ start, end });
|
|
5974
|
+
}
|
|
5642
5975
|
}
|
|
5643
5976
|
ts__default.default.forEachChild(node, visit);
|
|
5644
5977
|
};
|
|
@@ -5650,16 +5983,21 @@ function skeletonizeTypeScript(source, fileName = "file.ts") {
|
|
|
5650
5983
|
if (last && span.start < last.end) continue;
|
|
5651
5984
|
outermost.push(span);
|
|
5652
5985
|
}
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5986
|
+
const chunks = [];
|
|
5987
|
+
let cursor = 0;
|
|
5988
|
+
for (const span of outermost) {
|
|
5989
|
+
chunks.push(source.slice(cursor, span.start), "{ /* ... */ }");
|
|
5990
|
+
cursor = span.end;
|
|
5657
5991
|
}
|
|
5658
|
-
|
|
5992
|
+
chunks.push(source.slice(cursor));
|
|
5993
|
+
return { text: chunks.join(""), collapsed: outermost.length };
|
|
5659
5994
|
}
|
|
5660
5995
|
function isSkeletonizable(filePath) {
|
|
5661
5996
|
const lower = filePath.toLowerCase();
|
|
5662
|
-
|
|
5997
|
+
if (lower.endsWith(".d.ts") || lower.endsWith(".d.mts") || lower.endsWith(".d.cts")) {
|
|
5998
|
+
return false;
|
|
5999
|
+
}
|
|
6000
|
+
return lower.endsWith(".ts") || lower.endsWith(".tsx") || lower.endsWith(".mts") || lower.endsWith(".cts") || lower.endsWith(".js") || lower.endsWith(".jsx") || lower.endsWith(".mjs") || lower.endsWith(".cjs");
|
|
5663
6001
|
}
|
|
5664
6002
|
var SARIF_VERSION = "2.1.0";
|
|
5665
6003
|
var SARIF_SCHEMA = "https://json.schemastore.org/sarif-2.1.0.json";
|
|
@@ -5784,23 +6122,55 @@ function truncateWithBudgetMarker(content, maxBytes, budget, originalLines) {
|
|
|
5784
6122
|
};
|
|
5785
6123
|
}
|
|
5786
6124
|
function partitionFiles(files, maxPartBytes, contentFingerprint) {
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
const
|
|
5791
|
-
|
|
6125
|
+
return partitionFilesForBuckets([{ files, budgetBytes: maxPartBytes }], contentFingerprint);
|
|
6126
|
+
}
|
|
6127
|
+
function partitionFilesForBuckets(buckets, contentFingerprint) {
|
|
6128
|
+
const groups = [];
|
|
6129
|
+
for (const bucket of buckets) {
|
|
6130
|
+
if (bucket.files.length === 0) continue;
|
|
6131
|
+
const budget = Math.max(
|
|
6132
|
+
MIN_SECTION_BUDGET_BYTES + HEADER_RESERVE_BYTES,
|
|
6133
|
+
bucket.budgetBytes
|
|
6134
|
+
);
|
|
6135
|
+
const sectionBudget = budget - HEADER_RESERVE_BYTES;
|
|
6136
|
+
const prepared = bucket.files.map((file) => prepareSection(file, sectionBudget));
|
|
6137
|
+
for (const sections of greedyGroups(prepared, budget)) groups.push({ sections, budget });
|
|
6138
|
+
}
|
|
6139
|
+
if (groups.length === 0) return [];
|
|
6140
|
+
const measurements = /* @__PURE__ */ new Map();
|
|
6141
|
+
const widthOf = (total) => Math.max(3, String(total).length);
|
|
6142
|
+
const measure = (group, index, total) => {
|
|
6143
|
+
const cached = measurements.get(group);
|
|
6144
|
+
const width = widthOf(total);
|
|
6145
|
+
if (cached !== void 0 && cached.index === index && cached.width === width) {
|
|
6146
|
+
return cached.size;
|
|
6147
|
+
}
|
|
6148
|
+
const { content } = assembleGroup(group, index, total, contentFingerprint);
|
|
6149
|
+
const size = Buffer.byteLength(content, "utf8");
|
|
6150
|
+
measurements.set(group, { index, width, size });
|
|
6151
|
+
return size;
|
|
6152
|
+
};
|
|
5792
6153
|
for (let pass = 0; pass < MAX_SPLIT_PASSES; pass++) {
|
|
5793
|
-
const
|
|
5794
|
-
|
|
5795
|
-
|
|
6154
|
+
const total = groups.length;
|
|
6155
|
+
let oversized = -1;
|
|
6156
|
+
for (let index = 0; index < total; index += 1) {
|
|
6157
|
+
const group2 = groups[index];
|
|
6158
|
+
if (measure(group2, index, total) > group2.budget) {
|
|
6159
|
+
oversized = index;
|
|
6160
|
+
break;
|
|
6161
|
+
}
|
|
6162
|
+
}
|
|
6163
|
+
if (oversized === -1) return renderGroups(groups, contentFingerprint);
|
|
5796
6164
|
const group = groups[oversized];
|
|
5797
|
-
if (group.length > 1) {
|
|
5798
|
-
const moved = group.pop();
|
|
5799
|
-
groups.splice(oversized + 1, 0, [moved]);
|
|
6165
|
+
if (group.sections.length > 1) {
|
|
6166
|
+
const moved = group.sections.pop();
|
|
6167
|
+
groups.splice(oversized + 1, 0, { sections: [moved], budget: group.budget });
|
|
6168
|
+
measurements.delete(group);
|
|
5800
6169
|
continue;
|
|
5801
6170
|
}
|
|
5802
|
-
const [section] = group;
|
|
5803
|
-
|
|
6171
|
+
const [section] = group.sections;
|
|
6172
|
+
if (section === void 0) return renderGroups(groups, contentFingerprint);
|
|
6173
|
+
const overflow = measure(group, oversized, total) - group.budget;
|
|
5804
6174
|
const currentContent = section.file.content ?? "";
|
|
5805
6175
|
const shrinkTo = Math.max(
|
|
5806
6176
|
0,
|
|
@@ -5809,26 +6179,33 @@ function partitionFiles(files, maxPartBytes, contentFingerprint) {
|
|
|
5809
6179
|
const shrunk = truncateWithBudgetMarker(
|
|
5810
6180
|
currentContent,
|
|
5811
6181
|
shrinkTo,
|
|
5812
|
-
budget,
|
|
6182
|
+
group.budget,
|
|
5813
6183
|
section.file.originalLines
|
|
5814
6184
|
);
|
|
5815
6185
|
if (shrunk.isTruncated) {
|
|
5816
6186
|
applyTruncatedContent(section.file, shrunk.content);
|
|
5817
6187
|
section.text = renderFileSection(section.file);
|
|
5818
6188
|
section.byteSize = Buffer.byteLength(section.text, "utf8");
|
|
6189
|
+
measurements.delete(group);
|
|
5819
6190
|
continue;
|
|
5820
6191
|
}
|
|
6192
|
+
const rendered = renderGroups(groups, contentFingerprint);
|
|
5821
6193
|
const marker = TRUNCATION_MARKER;
|
|
5822
|
-
assertBudgetHoldsMarker(budget);
|
|
6194
|
+
assertBudgetHoldsMarker(group.budget);
|
|
5823
6195
|
const target = Math.max(
|
|
5824
6196
|
0,
|
|
5825
|
-
budget - Buffer.byteLength(marker, "utf8") - TOKEN_LINE_SLACK
|
|
6197
|
+
group.budget - Buffer.byteLength(marker, "utf8") - TOKEN_LINE_SLACK
|
|
5826
6198
|
);
|
|
5827
6199
|
const clipped = truncateToBytes(rendered[oversized].markdown, target);
|
|
5828
|
-
rendered[oversized] = rehashPart(
|
|
6200
|
+
rendered[oversized] = rehashPart(
|
|
6201
|
+
rendered[oversized],
|
|
6202
|
+
clipped.content + marker
|
|
6203
|
+
);
|
|
5829
6204
|
return rendered;
|
|
5830
6205
|
}
|
|
5831
|
-
return
|
|
6206
|
+
return renderGroups(groups, contentFingerprint).flatMap(
|
|
6207
|
+
(part) => enforceBudget([part], part.metadata.budgetBytes)
|
|
6208
|
+
);
|
|
5832
6209
|
}
|
|
5833
6210
|
var TRUNCATION_MARKER = "\n... [part truncated: cannot fit budget] ...\n";
|
|
5834
6211
|
function assertBudgetHoldsMarker(budget) {
|
|
@@ -5851,69 +6228,7 @@ function enforceBudget(parts, budget) {
|
|
|
5851
6228
|
return rehashPart(part, clipped.content + TRUNCATION_MARKER);
|
|
5852
6229
|
});
|
|
5853
6230
|
}
|
|
5854
|
-
|
|
5855
|
-
const total = parts.length;
|
|
5856
|
-
if (total === 0) return [];
|
|
5857
|
-
const zeroPad = (index) => String(index).padStart(Math.max(3, String(total).length), "0");
|
|
5858
|
-
const nameFor = (position) => `part-${zeroPad(position)}.md`;
|
|
5859
|
-
const marker = "## Contents\n";
|
|
5860
|
-
const renumbered = parts.map((part, index) => {
|
|
5861
|
-
const markerIndex = part.markdown.indexOf(marker);
|
|
5862
|
-
const body = markerIndex === -1 ? "" : part.markdown.slice(markerIndex + marker.length);
|
|
5863
|
-
const included = part.metadata.includedFiles;
|
|
5864
|
-
if (markerIndex === -1) {
|
|
5865
|
-
throw new Error(`${part.filename} has no "## Contents" section to re-number.`);
|
|
5866
|
-
}
|
|
5867
|
-
const layerCounts = {};
|
|
5868
|
-
const kindCounts = {};
|
|
5869
|
-
for (const file of included) {
|
|
5870
|
-
layerCounts[file.layer] = (layerCounts[file.layer] || 0) + 1;
|
|
5871
|
-
kindCounts[file.kind] = (kindCounts[file.kind] || 0) + 1;
|
|
5872
|
-
}
|
|
5873
|
-
const pathLines = included.map((file) => displayPath(file.relativePath));
|
|
5874
|
-
const listFence = fenceForText(pathLines.join("\n"), 3);
|
|
5875
|
-
const header = [
|
|
5876
|
-
`# Codebase Snapshot Part ${zeroPad(index + 1)} of ${zeroPad(total)}`,
|
|
5877
|
-
"",
|
|
5878
|
-
`- Previous: ${index === 0 ? "none" : nameFor(index)}`,
|
|
5879
|
-
`- Next: ${index === total - 1 ? "none" : nameFor(index + 2)}`,
|
|
5880
|
-
`- Files: ${included.length}`,
|
|
5881
|
-
`- Content Fingerprint: ${contentFingerprint || "none"}`,
|
|
5882
|
-
`- Layers: ${topEntries(layerCounts, 6) || "none"}`,
|
|
5883
|
-
`- Kinds: ${topEntries(kindCounts, 8) || "none"}`,
|
|
5884
|
-
"",
|
|
5885
|
-
UNTRUSTED_CONTENT_NOTICE,
|
|
5886
|
-
"",
|
|
5887
|
-
"## Files",
|
|
5888
|
-
"",
|
|
5889
|
-
`${listFence}text`,
|
|
5890
|
-
...pathLines,
|
|
5891
|
-
listFence,
|
|
5892
|
-
"",
|
|
5893
|
-
"## Contents",
|
|
5894
|
-
""
|
|
5895
|
-
].join("\n");
|
|
5896
|
-
const assembled = (header + body).replace(/\r\n/g, "\n");
|
|
5897
|
-
const estimatedTokens = estimateTokens(assembled);
|
|
5898
|
-
const markdown = insertTokenLine(assembled, estimatedTokens);
|
|
5899
|
-
const metadata = {
|
|
5900
|
-
...part.metadata,
|
|
5901
|
-
index: index + 1,
|
|
5902
|
-
filename: nameFor(index + 1),
|
|
5903
|
-
byteSize: Buffer.byteLength(markdown, "utf8"),
|
|
5904
|
-
estimatedTokens,
|
|
5905
|
-
sha256: crypto2__namespace.createHash("sha256").update(markdown).digest("hex"),
|
|
5906
|
-
lines: countLines(markdown),
|
|
5907
|
-
fileCount: included.length,
|
|
5908
|
-
layersCovered: Object.keys(layerCounts).sort()
|
|
5909
|
-
};
|
|
5910
|
-
return { filename: metadata.filename, markdown, metadata };
|
|
5911
|
-
});
|
|
5912
|
-
return renumbered.map(
|
|
5913
|
-
(part) => enforceBudget([part], part.metadata.budgetBytes)[0] ?? part
|
|
5914
|
-
);
|
|
5915
|
-
}
|
|
5916
|
-
var SECTION_TRUNCATION_NOTICE = "\n... [section truncated: metadata alone exceeds the part budget] ...\n";
|
|
6231
|
+
var SECTION_TRUNCATION_NOTICE = "... [section truncated: the fixed metadata and a code fence did not fit the part budget] ...";
|
|
5917
6232
|
var METADATA_VALUE_MAX = 200;
|
|
5918
6233
|
var DISPLAY_PATH_MAX = 300;
|
|
5919
6234
|
function capValue(value, max) {
|
|
@@ -5955,13 +6270,57 @@ function prepareSection(file, sectionBudget) {
|
|
|
5955
6270
|
shrinkBody();
|
|
5956
6271
|
}
|
|
5957
6272
|
if (byteSize > sectionBudget) {
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
6273
|
+
applyTruncatedContent(file, SECTION_TRUNCATION_NOTICE);
|
|
6274
|
+
file.summary = void 0;
|
|
6275
|
+
file.summaryOmitted = true;
|
|
6276
|
+
text = renderFileSection(file);
|
|
5961
6277
|
byteSize = Buffer.byteLength(text, "utf8");
|
|
6278
|
+
if (byteSize > sectionBudget) {
|
|
6279
|
+
text = truncateRenderedSection(text, sectionBudget, fenceForContent(file.content ?? ""));
|
|
6280
|
+
byteSize = Buffer.byteLength(text, "utf8");
|
|
6281
|
+
}
|
|
5962
6282
|
}
|
|
5963
6283
|
return { file, text, byteSize };
|
|
5964
6284
|
}
|
|
6285
|
+
function truncateRenderedSection(text, sectionBudget, fence) {
|
|
6286
|
+
const closing = `
|
|
6287
|
+
${SECTION_TRUNCATION_NOTICE}
|
|
6288
|
+
${fence}
|
|
6289
|
+
`;
|
|
6290
|
+
const bodyRoom = sectionBudget - Buffer.byteLength(closing, "utf8");
|
|
6291
|
+
if (bodyRoom > 0) {
|
|
6292
|
+
const cut2 = truncateToBytes(text, bodyRoom).content;
|
|
6293
|
+
const lastBreak2 = cut2.lastIndexOf("\n");
|
|
6294
|
+
const kept = lastBreak2 >= 0 ? cut2.slice(0, lastBreak2 + 1) : "";
|
|
6295
|
+
if (fenceIsOpen(kept, fence)) return `${kept}${closing}`;
|
|
6296
|
+
}
|
|
6297
|
+
const probe = text.slice(0, 512);
|
|
6298
|
+
const emptyFence = fenceForText(probe.slice(0, Math.max(0, probe.lastIndexOf("\n") + 1)), 4);
|
|
6299
|
+
const block = `
|
|
6300
|
+
${emptyFence}
|
|
6301
|
+
${SECTION_TRUNCATION_NOTICE}
|
|
6302
|
+
${emptyFence}
|
|
6303
|
+
`;
|
|
6304
|
+
const prefixRoom = sectionBudget - Buffer.byteLength(block, "utf8");
|
|
6305
|
+
const cut = prefixRoom > 0 ? truncateToBytes(text, prefixRoom).content : "";
|
|
6306
|
+
const lastBreak = cut.lastIndexOf("\n");
|
|
6307
|
+
const prefix = lastBreak >= 0 ? cut.slice(0, lastBreak + 1) : "";
|
|
6308
|
+
return `${dropTrailingOpenFence(prefix, fence)}${block}`;
|
|
6309
|
+
}
|
|
6310
|
+
function dropTrailingOpenFence(text, fence) {
|
|
6311
|
+
if (!fenceIsOpen(text, fence)) return text;
|
|
6312
|
+
const lines = text.split("\n");
|
|
6313
|
+
const opening = lines.findIndex((line) => line.startsWith(fence));
|
|
6314
|
+
if (opening < 0) return text;
|
|
6315
|
+
return lines.slice(0, opening).join("\n") + (opening > 0 ? "\n" : "");
|
|
6316
|
+
}
|
|
6317
|
+
function fenceIsOpen(text, fence) {
|
|
6318
|
+
let open = false;
|
|
6319
|
+
for (const line of text.split("\n")) {
|
|
6320
|
+
if (line.startsWith(fence)) open = !open;
|
|
6321
|
+
}
|
|
6322
|
+
return open;
|
|
6323
|
+
}
|
|
5965
6324
|
function applyTruncatedContent(file, content) {
|
|
5966
6325
|
file.content = content;
|
|
5967
6326
|
file.isPreviewTruncated = true;
|
|
@@ -6009,52 +6368,64 @@ function greedyGroups(sections, budget) {
|
|
|
6009
6368
|
if (current.length > 0) groups.push(current);
|
|
6010
6369
|
return groups;
|
|
6011
6370
|
}
|
|
6012
|
-
function
|
|
6371
|
+
function assembleGroup(group, index, total, contentFingerprint) {
|
|
6372
|
+
const width = Math.max(3, String(total).length);
|
|
6373
|
+
const zeroPad = (value) => String(value).padStart(width, "0");
|
|
6374
|
+
const filename = `part-${zeroPad(index + 1)}.md`;
|
|
6375
|
+
const prev = index === 0 ? "none" : `part-${zeroPad(index)}.md`;
|
|
6376
|
+
const next = index === total - 1 ? "none" : `part-${zeroPad(index + 2)}.md`;
|
|
6377
|
+
for (const section of group.sections) {
|
|
6378
|
+
section.file.part = filename;
|
|
6379
|
+
}
|
|
6380
|
+
const layerCounts = {};
|
|
6381
|
+
const kindCounts = {};
|
|
6382
|
+
for (const section of group.sections) {
|
|
6383
|
+
layerCounts[section.file.layer] = (layerCounts[section.file.layer] || 0) + 1;
|
|
6384
|
+
kindCounts[section.file.kind] = (kindCounts[section.file.kind] || 0) + 1;
|
|
6385
|
+
}
|
|
6386
|
+
const pathLines = group.sections.map((s) => displayPath(s.file.relativePath));
|
|
6387
|
+
const listFence = fenceForText(pathLines.join("\n"), 3);
|
|
6388
|
+
const header = [
|
|
6389
|
+
`# Codebase Snapshot Part ${zeroPad(index + 1)} of ${zeroPad(total)}`,
|
|
6390
|
+
"",
|
|
6391
|
+
`- Previous: ${prev}`,
|
|
6392
|
+
`- Next: ${next}`,
|
|
6393
|
+
`- Files: ${group.sections.length}`,
|
|
6394
|
+
`- Content Fingerprint: ${contentFingerprint || "none"}`,
|
|
6395
|
+
`- Layers: ${topEntries(layerCounts, 6) || "none"}`,
|
|
6396
|
+
`- Kinds: ${topEntries(kindCounts, 8) || "none"}`,
|
|
6397
|
+
"",
|
|
6398
|
+
UNTRUSTED_CONTENT_NOTICE,
|
|
6399
|
+
"",
|
|
6400
|
+
"## Files",
|
|
6401
|
+
"",
|
|
6402
|
+
`${listFence}text`,
|
|
6403
|
+
...pathLines,
|
|
6404
|
+
listFence,
|
|
6405
|
+
"",
|
|
6406
|
+
"## Contents",
|
|
6407
|
+
""
|
|
6408
|
+
].join("\n");
|
|
6409
|
+
const assembled = (header + group.sections.map((s) => s.text).join("")).replace(
|
|
6410
|
+
/\r\n|\r/g,
|
|
6411
|
+
"\n"
|
|
6412
|
+
);
|
|
6413
|
+
const estimatedTokens = estimateTokens(assembled);
|
|
6414
|
+
return { filename, content: insertTokenLine(assembled, estimatedTokens), estimatedTokens };
|
|
6415
|
+
}
|
|
6416
|
+
function renderGroups(groups, contentFingerprint) {
|
|
6013
6417
|
const total = groups.length;
|
|
6014
|
-
const zeroPad = (index) => String(index).padStart(Math.max(3, String(total).length), "0");
|
|
6015
6418
|
return groups.map((group, index) => {
|
|
6016
|
-
const filename =
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
const layersCovered = Array.from(new Set(group.map((s) => s.file.layer))).sort();
|
|
6023
|
-
const layerCounts = {};
|
|
6024
|
-
const kindCounts = {};
|
|
6025
|
-
for (const section of group) {
|
|
6026
|
-
layerCounts[section.file.layer] = (layerCounts[section.file.layer] || 0) + 1;
|
|
6027
|
-
kindCounts[section.file.kind] = (kindCounts[section.file.kind] || 0) + 1;
|
|
6028
|
-
}
|
|
6029
|
-
const pathLines = group.map((s) => displayPath(s.file.relativePath));
|
|
6030
|
-
const listFence = fenceForText(pathLines.join("\n"), 3);
|
|
6031
|
-
const header = [
|
|
6032
|
-
`# Codebase Snapshot Part ${zeroPad(index + 1)} of ${zeroPad(total)}`,
|
|
6033
|
-
"",
|
|
6034
|
-
`- Previous: ${prev}`,
|
|
6035
|
-
`- Next: ${next}`,
|
|
6036
|
-
`- Files: ${group.length}`,
|
|
6037
|
-
`- Content Fingerprint: ${contentFingerprint || "none"}`,
|
|
6038
|
-
`- Layers: ${topEntries(layerCounts, 6) || "none"}`,
|
|
6039
|
-
`- Kinds: ${topEntries(kindCounts, 8) || "none"}`,
|
|
6040
|
-
"",
|
|
6041
|
-
UNTRUSTED_CONTENT_NOTICE,
|
|
6042
|
-
"",
|
|
6043
|
-
"## Files",
|
|
6044
|
-
"",
|
|
6045
|
-
`${listFence}text`,
|
|
6046
|
-
...pathLines,
|
|
6047
|
-
listFence,
|
|
6048
|
-
"",
|
|
6049
|
-
"## Contents",
|
|
6050
|
-
""
|
|
6051
|
-
].join("\n");
|
|
6052
|
-
const assembled = (header + group.map((s) => s.text).join("")).replace(/\r\n/g, "\n");
|
|
6053
|
-
const estimatedTokens = estimateTokens(assembled);
|
|
6054
|
-
const content = insertTokenLine(assembled, estimatedTokens);
|
|
6419
|
+
const { filename, content, estimatedTokens } = assembleGroup(
|
|
6420
|
+
group,
|
|
6421
|
+
index,
|
|
6422
|
+
total,
|
|
6423
|
+
contentFingerprint
|
|
6424
|
+
);
|
|
6055
6425
|
const byteSize = Buffer.byteLength(content, "utf8");
|
|
6056
6426
|
const sha256 = crypto2__namespace.createHash("sha256").update(content).digest("hex");
|
|
6057
|
-
const
|
|
6427
|
+
const layersCovered = Array.from(new Set(group.sections.map((s) => s.file.layer))).sort();
|
|
6428
|
+
const includedFiles = group.sections.map(({ file }) => ({
|
|
6058
6429
|
relativePath: file.relativePath,
|
|
6059
6430
|
sourceBytes: file.sizeBytes,
|
|
6060
6431
|
includedBytes: file.includedBytes,
|
|
@@ -6067,10 +6438,10 @@ function renderGroups(groups, budget, contentFingerprint) {
|
|
|
6067
6438
|
filename,
|
|
6068
6439
|
byteSize,
|
|
6069
6440
|
estimatedTokens,
|
|
6070
|
-
budgetBytes: budget,
|
|
6441
|
+
budgetBytes: group.budget,
|
|
6071
6442
|
sha256,
|
|
6072
6443
|
lines: countLines(content),
|
|
6073
|
-
fileCount: group.length,
|
|
6444
|
+
fileCount: group.sections.length,
|
|
6074
6445
|
layersCovered,
|
|
6075
6446
|
includedFiles
|
|
6076
6447
|
};
|
|
@@ -6078,7 +6449,7 @@ function renderGroups(groups, budget, contentFingerprint) {
|
|
|
6078
6449
|
});
|
|
6079
6450
|
}
|
|
6080
6451
|
function emittedBody(content) {
|
|
6081
|
-
const normalised = content.replace(/\r\n/g, "\n");
|
|
6452
|
+
const normalised = content.replace(/\r\n|\r/g, "\n");
|
|
6082
6453
|
return normalised.endsWith("\n") ? normalised.slice(0, -1) : normalised;
|
|
6083
6454
|
}
|
|
6084
6455
|
function compactMetadata(file) {
|
|
@@ -6146,7 +6517,7 @@ function generateMonolithJson(manifest, filesWithContent) {
|
|
|
6146
6517
|
}
|
|
6147
6518
|
function generateMonolithMarkdown(manifest, filesWithContent) {
|
|
6148
6519
|
const sections = filesWithContent.map((file) => {
|
|
6149
|
-
const content = (file.content ?? "").replace(/\r\n/g, "\n");
|
|
6520
|
+
const content = (file.content ?? "").replace(/\r\n|\r/g, "\n");
|
|
6150
6521
|
const fence = fenceForContent(content);
|
|
6151
6522
|
return [
|
|
6152
6523
|
`## File: ${escapeControls(file.relativePath)}`,
|
|
@@ -6365,9 +6736,13 @@ function describeManifestShapeProblem(value) {
|
|
|
6365
6736
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
6366
6737
|
return 'a "parts" entry is not an object';
|
|
6367
6738
|
}
|
|
6368
|
-
|
|
6739
|
+
const filename = entry.filename;
|
|
6740
|
+
if (typeof filename !== "string" || filename.trim() === "") {
|
|
6369
6741
|
return 'a "parts" entry has no "filename"';
|
|
6370
6742
|
}
|
|
6743
|
+
if (filename.includes("/") || filename.includes("\\") || filename.includes("\0") || filename === "." || filename === ".." || path10__namespace.isAbsolute(filename)) {
|
|
6744
|
+
return 'a "parts" entry "filename" must be a bare filename inside parts/';
|
|
6745
|
+
}
|
|
6371
6746
|
}
|
|
6372
6747
|
if (!candidate.layers || typeof candidate.layers !== "object" || Array.isArray(candidate.layers)) {
|
|
6373
6748
|
return 'missing "layers" object';
|
|
@@ -6478,7 +6853,7 @@ function validateSnapshot(configInput) {
|
|
|
6478
6853
|
});
|
|
6479
6854
|
for (const diskFile of collection.files) {
|
|
6480
6855
|
const snapshotHash = manifestFileMap.get(diskFile);
|
|
6481
|
-
if (
|
|
6856
|
+
if (snapshotHash === void 0) {
|
|
6482
6857
|
const skipReason = skippedReasonOnDisk(diskFile);
|
|
6483
6858
|
if (skipReason === "unchanged") {
|
|
6484
6859
|
if (unchangedScope !== null) {
|
|
@@ -6492,6 +6867,11 @@ function validateSnapshot(configInput) {
|
|
|
6492
6867
|
drift.missingInSnapshot.push(diskFile);
|
|
6493
6868
|
continue;
|
|
6494
6869
|
}
|
|
6870
|
+
if (unchangedScope !== null && !unchangedScope.has(diskFile) && !becameDependent(diskFile)) {
|
|
6871
|
+
drift.configMismatches.push(
|
|
6872
|
+
`scope: ${maskedPath(diskFile, config.secretRules)} is in the snapshot but is no longer in the changed-files scope`
|
|
6873
|
+
);
|
|
6874
|
+
}
|
|
6495
6875
|
let diskHash;
|
|
6496
6876
|
try {
|
|
6497
6877
|
diskHash = sha256Hex(fs8__namespace.readFileSync(path10__namespace.join(config.cwd, diskFile)));
|
|
@@ -6632,6 +7012,41 @@ function validateSnapshot(configInput) {
|
|
|
6632
7012
|
`includeSensitiveFiles: manifest ${recorded.includeSensitiveFiles} vs current ${config.includeSensitiveFiles}`
|
|
6633
7013
|
);
|
|
6634
7014
|
}
|
|
7015
|
+
if ((recorded.maxPartTokens ?? void 0) !== (config.maxPartTokens ?? void 0)) {
|
|
7016
|
+
drift.configMismatches.push(
|
|
7017
|
+
`maxPartTokens: manifest ${String(recorded.maxPartTokens ?? "unset")} vs current ${String(config.maxPartTokens ?? "unset")}`
|
|
7018
|
+
);
|
|
7019
|
+
}
|
|
7020
|
+
if ((recorded.maxMonolithBytes ?? null) !== (config.maxMonolithBytes ?? null)) {
|
|
7021
|
+
drift.configMismatches.push(
|
|
7022
|
+
`maxMonolithBytes: manifest ${String(recorded.maxMonolithBytes ?? null)} vs current ${String(config.maxMonolithBytes ?? null)}`
|
|
7023
|
+
);
|
|
7024
|
+
}
|
|
7025
|
+
if (Boolean(recorded.skeleton) !== Boolean(config.skeleton)) {
|
|
7026
|
+
drift.configMismatches.push(
|
|
7027
|
+
`skeleton: manifest ${Boolean(recorded.skeleton)} vs current ${Boolean(config.skeleton)}`
|
|
7028
|
+
);
|
|
7029
|
+
}
|
|
7030
|
+
if (Boolean(recorded.sarif) !== Boolean(config.sarif)) {
|
|
7031
|
+
drift.configMismatches.push(
|
|
7032
|
+
`sarif: manifest ${Boolean(recorded.sarif)} vs current ${Boolean(config.sarif)}`
|
|
7033
|
+
);
|
|
7034
|
+
}
|
|
7035
|
+
if ((recorded.changedSince ?? void 0) !== (config.changedSince ?? void 0)) {
|
|
7036
|
+
drift.configMismatches.push(
|
|
7037
|
+
`changedSince: manifest ${String(recorded.changedSince ?? "unset")} vs current ${String(config.changedSince ?? "unset")}`
|
|
7038
|
+
);
|
|
7039
|
+
}
|
|
7040
|
+
if (Boolean(recorded.staged) !== Boolean(config.staged)) {
|
|
7041
|
+
drift.configMismatches.push(
|
|
7042
|
+
`staged: manifest ${Boolean(recorded.staged)} vs current ${Boolean(config.staged)}`
|
|
7043
|
+
);
|
|
7044
|
+
}
|
|
7045
|
+
if (Boolean(recorded.withDependents) !== Boolean(config.withDependents)) {
|
|
7046
|
+
drift.configMismatches.push(
|
|
7047
|
+
`withDependents: manifest ${Boolean(recorded.withDependents)} vs current ${Boolean(config.withDependents)}`
|
|
7048
|
+
);
|
|
7049
|
+
}
|
|
6635
7050
|
const effectiveDiscovery = config.discovery ?? "auto";
|
|
6636
7051
|
const recordedDiscovery = recorded.discovery;
|
|
6637
7052
|
if (recordedDiscovery !== void 0 && recordedDiscovery !== effectiveDiscovery) {
|
|
@@ -6852,7 +7267,7 @@ function validateSnapshot(configInput) {
|
|
|
6852
7267
|
|
|
6853
7268
|
// src/version.ts
|
|
6854
7269
|
var GENERATOR_NAME = "codebase-snapshot";
|
|
6855
|
-
var GENERATOR_VERSION = "0.9.
|
|
7270
|
+
var GENERATOR_VERSION = "0.9.14";
|
|
6856
7271
|
var LEGACY_GENERATOR_NAMES = ["@ankurhalder/codebase-snapshot"];
|
|
6857
7272
|
function isOurGeneratorName(name) {
|
|
6858
7273
|
if (typeof name !== "string") return false;
|
|
@@ -6873,7 +7288,10 @@ const { parentPort, workerData } = require("node:worker_threads");
|
|
|
6873
7288
|
parentPort.postMessage({ ok: false, message: loaded.errors.join("; ") });
|
|
6874
7289
|
return;
|
|
6875
7290
|
}
|
|
6876
|
-
|
|
7291
|
+
// \`hooks: {}\` is a value, not an absence: the config is applied with the hook list emptied,
|
|
7292
|
+
// so the run is the documented MCP run rather than the CLI run with one setting removed.
|
|
7293
|
+
const base = loaded.config ? { ...loaded.config, hooks: {} } : null;
|
|
7294
|
+
const config = mod.resolveConfig(base, workerData.cliOptions, workerData.cwd);
|
|
6877
7295
|
const manifest = mod.generateSnapshot(config);
|
|
6878
7296
|
parentPort.postMessage({
|
|
6879
7297
|
ok: true,
|
|
@@ -6896,14 +7314,15 @@ const { parentPort, workerData } = require("node:worker_threads");
|
|
|
6896
7314
|
})();
|
|
6897
7315
|
`;
|
|
6898
7316
|
function generateInWorker(cwd, cliOptions) {
|
|
6899
|
-
return new Promise((
|
|
7317
|
+
return new Promise((resolve9) => {
|
|
6900
7318
|
let settled = false;
|
|
7319
|
+
let worker = null;
|
|
6901
7320
|
const finish = (result) => {
|
|
6902
7321
|
if (settled) return;
|
|
6903
7322
|
settled = true;
|
|
6904
|
-
|
|
7323
|
+
if (worker !== null) void worker.terminate();
|
|
7324
|
+
resolve9(result);
|
|
6905
7325
|
};
|
|
6906
|
-
let worker;
|
|
6907
7326
|
const isCjs = typeof __dirname !== "undefined";
|
|
6908
7327
|
const directory = isCjs ? __dirname : path10__namespace.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('mcp.cjs', document.baseURI).href))));
|
|
6909
7328
|
try {
|
|
@@ -6936,7 +7355,100 @@ function generateInWorker(cwd, cliOptions) {
|
|
|
6936
7355
|
|
|
6937
7356
|
// src/index.ts
|
|
6938
7357
|
var SCHEMA_VERSION = "3.0.0";
|
|
6939
|
-
var
|
|
7358
|
+
var SUMMARY_MAX_SOURCE_BYTES2 = SUMMARY_MAX_SOURCE_BYTES;
|
|
7359
|
+
var FILE_DERIVATIONS = /* @__PURE__ */ new Map();
|
|
7360
|
+
var FILE_DERIVATION_LIMIT_BYTES = 64 * 1024 * 1024;
|
|
7361
|
+
var fileDerivationBytes = 0;
|
|
7362
|
+
function takeDerivation(path14, hash, settings) {
|
|
7363
|
+
const cached = FILE_DERIVATIONS.get(path14);
|
|
7364
|
+
if (cached === void 0 || cached.hash !== hash || cached.settings !== settings) return void 0;
|
|
7365
|
+
return cached;
|
|
7366
|
+
}
|
|
7367
|
+
function rememberDerivation(path14, hash, settings, derivation) {
|
|
7368
|
+
const bodyBytes = derivation.finalContent === derivation.redacted ? derivation.redacted.length : derivation.redacted.length + derivation.finalContent.length;
|
|
7369
|
+
const bytes = bodyBytes * 2 + 512;
|
|
7370
|
+
if (bytes > FILE_DERIVATION_LIMIT_BYTES / 4) return;
|
|
7371
|
+
while (fileDerivationBytes + bytes > FILE_DERIVATION_LIMIT_BYTES) {
|
|
7372
|
+
const oldest = FILE_DERIVATIONS.keys().next();
|
|
7373
|
+
if (oldest.done === true) break;
|
|
7374
|
+
const evicted = FILE_DERIVATIONS.get(oldest.value);
|
|
7375
|
+
FILE_DERIVATIONS.delete(oldest.value);
|
|
7376
|
+
if (evicted !== void 0) fileDerivationBytes -= evicted.bytes;
|
|
7377
|
+
}
|
|
7378
|
+
FILE_DERIVATIONS.set(path14, { ...derivation, hash, settings, bytes });
|
|
7379
|
+
fileDerivationBytes += bytes;
|
|
7380
|
+
}
|
|
7381
|
+
function derivationSettings(config) {
|
|
7382
|
+
const rules = config.secretRules.map(
|
|
7383
|
+
(rule) => `${rule.rule}\0${rule.pattern.source}\0${rule.pattern.flags}\0${rule.valueGroup ?? ""}`
|
|
7384
|
+
).join("");
|
|
7385
|
+
return `${GENERATOR_VERSION}${configDigest(config)}${sha256Hex2(rules)}`;
|
|
7386
|
+
}
|
|
7387
|
+
function deriveFile(relativePath, rawContent, sizeBytes, config) {
|
|
7388
|
+
const lineCount = countLines(rawContent);
|
|
7389
|
+
const { redacted, findings } = scanAndRedactSecrets(rawContent, config.secretRules, relativePath);
|
|
7390
|
+
const isLarge = sizeBytes > config.largeFileBytes;
|
|
7391
|
+
let finalContent = redacted;
|
|
7392
|
+
let isPreviewTruncated = false;
|
|
7393
|
+
let includedLines = lineCount;
|
|
7394
|
+
let inclusionMode = "full";
|
|
7395
|
+
if (config.skeleton === true && isSkeletonizable(relativePath)) {
|
|
7396
|
+
const skeleton = skeletonizeTypeScript(redacted, relativePath);
|
|
7397
|
+
if (skeleton.collapsed > 0) {
|
|
7398
|
+
finalContent = skeleton.text;
|
|
7399
|
+
inclusionMode = "signatures";
|
|
7400
|
+
includedLines = countLines(skeleton.text);
|
|
7401
|
+
}
|
|
7402
|
+
}
|
|
7403
|
+
if (isLarge && inclusionMode !== "signatures") {
|
|
7404
|
+
const preview = truncatePreview(redacted, config.previewHeadLines, config.previewTailLines);
|
|
7405
|
+
finalContent = preview.content;
|
|
7406
|
+
isPreviewTruncated = preview.isTruncated;
|
|
7407
|
+
includedLines = preview.includedLines;
|
|
7408
|
+
inclusionMode = isPreviewTruncated ? "preview" : "full";
|
|
7409
|
+
}
|
|
7410
|
+
let summary;
|
|
7411
|
+
let summaryQuality;
|
|
7412
|
+
let summarySkip = null;
|
|
7413
|
+
let summaryWarning = null;
|
|
7414
|
+
let dependentImports = null;
|
|
7415
|
+
if (Buffer.byteLength(rawContent, "utf8") > SUMMARY_MAX_SOURCE_BYTES2) {
|
|
7416
|
+
summarySkip = "oversize";
|
|
7417
|
+
dependentImports = [];
|
|
7418
|
+
} else if (isPreviewTruncated && hasStructuralSummary(relativePath)) {
|
|
7419
|
+
summarySkip = "preview";
|
|
7420
|
+
dependentImports = importsOfText(relativePath, rawContent);
|
|
7421
|
+
} else {
|
|
7422
|
+
try {
|
|
7423
|
+
const outcome = summarizeFile(relativePath, rawContent);
|
|
7424
|
+
summary = outcome?.summary ? maskSummaryStrings(outcome.summary, config.secretRules) : void 0;
|
|
7425
|
+
summaryQuality = outcome?.quality;
|
|
7426
|
+
if (isSourceSummary(summary) && summary.parseErrors) {
|
|
7427
|
+
summaryWarning = `Parse errors in ${maskPathText(relativePath, config.secretRules)} (${summary.parseErrors}); its summary is incomplete.`;
|
|
7428
|
+
}
|
|
7429
|
+
} catch (err) {
|
|
7430
|
+
summaryWarning = `Summary skipped for ${maskPathText(relativePath, config.secretRules)}: ${err.message}`.replace(
|
|
7431
|
+
/\s+/g,
|
|
7432
|
+
" "
|
|
7433
|
+
);
|
|
7434
|
+
}
|
|
7435
|
+
}
|
|
7436
|
+
return {
|
|
7437
|
+
redacted,
|
|
7438
|
+
findings,
|
|
7439
|
+
lineCount,
|
|
7440
|
+
finalContent,
|
|
7441
|
+
inclusionMode,
|
|
7442
|
+
isPreviewTruncated,
|
|
7443
|
+
includedLines,
|
|
7444
|
+
isLarge,
|
|
7445
|
+
summary,
|
|
7446
|
+
summaryQuality,
|
|
7447
|
+
summarySkip,
|
|
7448
|
+
summaryWarning,
|
|
7449
|
+
dependentImports
|
|
7450
|
+
};
|
|
7451
|
+
}
|
|
6940
7452
|
function sha256Hex2(input) {
|
|
6941
7453
|
return crypto2__namespace.createHash("sha256").update(input).digest("hex");
|
|
6942
7454
|
}
|
|
@@ -7393,23 +7905,14 @@ function partitionByBudget(files, config, fingerprint) {
|
|
|
7393
7905
|
if (bucket) bucket.push(file);
|
|
7394
7906
|
else buckets.set(budget, [file]);
|
|
7395
7907
|
}
|
|
7396
|
-
if (buckets.size
|
|
7397
|
-
|
|
7398
|
-
return partitionFiles(files,
|
|
7399
|
-
}
|
|
7400
|
-
const parts = [];
|
|
7401
|
-
for (const budget of Array.from(buckets.keys()).sort((a, b) => a - b)) {
|
|
7402
|
-
parts.push(...partitionFiles(buckets.get(budget) ?? [], budget, fingerprint));
|
|
7403
|
-
}
|
|
7404
|
-
const merged = renumberParts(parts, fingerprint);
|
|
7405
|
-
const byPath = new Map(files.map((file) => [file.relativePath, file]));
|
|
7406
|
-
for (const part of merged) {
|
|
7407
|
-
for (const included of part.metadata.includedFiles) {
|
|
7408
|
-
const file = byPath.get(included.relativePath);
|
|
7409
|
-
if (file) file.part = part.filename;
|
|
7410
|
-
}
|
|
7908
|
+
if (buckets.size === 0) return [];
|
|
7909
|
+
if (buckets.size === 1) {
|
|
7910
|
+
return partitionFiles(files, Array.from(buckets.keys())[0], fingerprint);
|
|
7411
7911
|
}
|
|
7412
|
-
return
|
|
7912
|
+
return partitionFilesForBuckets(
|
|
7913
|
+
Array.from(buckets.entries()).sort(([left], [right]) => left - right).map(([budgetBytes, bucketFiles]) => ({ files: bucketFiles, budgetBytes })),
|
|
7914
|
+
fingerprint
|
|
7915
|
+
);
|
|
7413
7916
|
}
|
|
7414
7917
|
function generateSnapshot(configInput, options) {
|
|
7415
7918
|
assertUsableConfigInput(configInput);
|
|
@@ -7440,6 +7943,7 @@ function generateSnapshot(configInput, options) {
|
|
|
7440
7943
|
return false;
|
|
7441
7944
|
}) : collection.files;
|
|
7442
7945
|
const files = [];
|
|
7946
|
+
const derivationKey = derivationSettings(config);
|
|
7443
7947
|
const monolithBodies = /* @__PURE__ */ new Map();
|
|
7444
7948
|
const skipped = maskSkipRecords([...collection.skipped], config.secretRules);
|
|
7445
7949
|
const secretFindings = [];
|
|
@@ -7452,6 +7956,7 @@ function generateSnapshot(configInput, options) {
|
|
|
7452
7956
|
const fileWarnings = [];
|
|
7453
7957
|
const oversizeSummaryPaths = [];
|
|
7454
7958
|
const previewSummaryPaths = [];
|
|
7959
|
+
const skippedSummaryImports = /* @__PURE__ */ new Map();
|
|
7455
7960
|
const layerCounts = {};
|
|
7456
7961
|
const kindCounts = {};
|
|
7457
7962
|
let totalLines = 0;
|
|
@@ -7516,8 +8021,6 @@ function generateSnapshot(configInput, options) {
|
|
|
7516
8021
|
}
|
|
7517
8022
|
const hashSha256 = sha256Hex2(buffer);
|
|
7518
8023
|
const rawContent = decoded.text;
|
|
7519
|
-
const lineCount = countLines(rawContent);
|
|
7520
|
-
totalLines += lineCount;
|
|
7521
8024
|
totalSizeBytes += stats.size;
|
|
7522
8025
|
if (decoded.encoding !== "utf-8") {
|
|
7523
8026
|
encodingNotes.push({
|
|
@@ -7531,66 +8034,25 @@ function generateSnapshot(configInput, options) {
|
|
|
7531
8034
|
const language = detectLanguage(relativePath);
|
|
7532
8035
|
bump(layerCounts, layer2);
|
|
7533
8036
|
bump(kindCounts, kind);
|
|
7534
|
-
const
|
|
7535
|
-
rawContent,
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
);
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
}
|
|
7554
|
-
if (isLarge && inclusionMode !== "signatures") {
|
|
7555
|
-
const preview = truncatePreview(
|
|
7556
|
-
redacted,
|
|
7557
|
-
config.previewHeadLines,
|
|
7558
|
-
config.previewTailLines
|
|
7559
|
-
);
|
|
7560
|
-
finalContent = preview.content;
|
|
7561
|
-
isPreviewTruncated = preview.isTruncated;
|
|
7562
|
-
includedLines = preview.includedLines;
|
|
7563
|
-
inclusionMode = isPreviewTruncated ? "preview" : "full";
|
|
7564
|
-
}
|
|
7565
|
-
if (config.includeMonolith && (isPreviewTruncated || inclusionMode === "signatures")) {
|
|
7566
|
-
monolithBodies.set(relativePath, redacted);
|
|
7567
|
-
}
|
|
7568
|
-
let summary;
|
|
7569
|
-
let summaryQuality;
|
|
7570
|
-
if (Buffer.byteLength(rawContent, "utf8") > SUMMARY_MAX_SOURCE_BYTES) {
|
|
7571
|
-
oversizeSummaryPaths.push(relativePath);
|
|
7572
|
-
} else if (isPreviewTruncated && hasStructuralSummary(relativePath)) {
|
|
7573
|
-
previewSummaryPaths.push(relativePath);
|
|
7574
|
-
} else {
|
|
7575
|
-
try {
|
|
7576
|
-
const outcome = summarizeFile(relativePath, rawContent);
|
|
7577
|
-
summary = outcome?.summary ? maskSummaryStrings(outcome.summary, config.secretRules) : void 0;
|
|
7578
|
-
summaryQuality = outcome?.quality;
|
|
7579
|
-
if (isSourceSummary(summary) && summary.parseErrors) {
|
|
7580
|
-
fileWarnings.push({
|
|
7581
|
-
path: relativePath,
|
|
7582
|
-
message: `Parse errors in ${maskPathText(relativePath, config.secretRules)} (${summary.parseErrors}); its summary is incomplete.`
|
|
7583
|
-
});
|
|
7584
|
-
}
|
|
7585
|
-
} catch (err) {
|
|
7586
|
-
fileWarnings.push({
|
|
7587
|
-
path: relativePath,
|
|
7588
|
-
message: `Summary skipped for ${maskPathText(relativePath, config.secretRules)}: ${err.message}`.replace(
|
|
7589
|
-
/\s+/g,
|
|
7590
|
-
" "
|
|
7591
|
-
)
|
|
7592
|
-
});
|
|
7593
|
-
}
|
|
8037
|
+
const derivation = takeDerivation(absolutePath, hashSha256, derivationKey) ?? (() => {
|
|
8038
|
+
const fresh = deriveFile(relativePath, rawContent, stats.size, config);
|
|
8039
|
+
rememberDerivation(absolutePath, hashSha256, derivationKey, fresh);
|
|
8040
|
+
return fresh;
|
|
8041
|
+
})();
|
|
8042
|
+
const { lineCount } = derivation;
|
|
8043
|
+
totalLines += lineCount;
|
|
8044
|
+
secretFindings.push(...derivation.findings);
|
|
8045
|
+
if (derivation.isLarge) largeFileCount += 1;
|
|
8046
|
+
if (derivation.summarySkip === "oversize") oversizeSummaryPaths.push(relativePath);
|
|
8047
|
+
else if (derivation.summarySkip === "preview") previewSummaryPaths.push(relativePath);
|
|
8048
|
+
if (derivation.dependentImports !== null) {
|
|
8049
|
+
skippedSummaryImports.set(relativePath, derivation.dependentImports);
|
|
8050
|
+
}
|
|
8051
|
+
if (derivation.summaryWarning !== null) {
|
|
8052
|
+
fileWarnings.push({ path: relativePath, message: derivation.summaryWarning });
|
|
8053
|
+
}
|
|
8054
|
+
if (config.includeMonolith && (derivation.isPreviewTruncated || derivation.inclusionMode === "signatures")) {
|
|
8055
|
+
monolithBodies.set(relativePath, derivation.redacted);
|
|
7594
8056
|
}
|
|
7595
8057
|
files.push({
|
|
7596
8058
|
relativePath,
|
|
@@ -7601,24 +8063,25 @@ function generateSnapshot(configInput, options) {
|
|
|
7601
8063
|
layer: layer2,
|
|
7602
8064
|
kind,
|
|
7603
8065
|
language,
|
|
7604
|
-
inclusionMode,
|
|
7605
|
-
isLarge,
|
|
7606
|
-
isPreviewTruncated,
|
|
8066
|
+
inclusionMode: derivation.inclusionMode,
|
|
8067
|
+
isLarge: derivation.isLarge,
|
|
8068
|
+
isPreviewTruncated: derivation.isPreviewTruncated,
|
|
7607
8069
|
originalLines: lineCount,
|
|
7608
|
-
includedLines,
|
|
7609
|
-
includedBytes: Buffer.byteLength(finalContent, "utf8"),
|
|
7610
|
-
summary,
|
|
7611
|
-
summaryQuality,
|
|
8070
|
+
includedLines: derivation.includedLines,
|
|
8071
|
+
includedBytes: Buffer.byteLength(derivation.finalContent, "utf8"),
|
|
8072
|
+
summary: derivation.summary,
|
|
8073
|
+
summaryQuality: derivation.summaryQuality,
|
|
7612
8074
|
...decoded.encoding === "utf-8" ? {} : { encoding: decoded.encoding },
|
|
7613
|
-
content: finalContent
|
|
8075
|
+
content: derivation.finalContent
|
|
7614
8076
|
});
|
|
7615
8077
|
}
|
|
7616
8078
|
if (changedScope !== null && changedPaths !== null && config.withDependents === true) {
|
|
7617
8079
|
const keep = new Set(changedPaths);
|
|
7618
8080
|
const resolver = buildImportResolver(files);
|
|
7619
8081
|
for (const file of files) {
|
|
7620
|
-
|
|
7621
|
-
if (
|
|
8082
|
+
const fileImports = isSourceSummary(file.summary) ? file.summary.imports : skippedSummaryImports.get(file.relativePath) ?? [];
|
|
8083
|
+
if (fileImports.length === 0) continue;
|
|
8084
|
+
if (importsChangedFile(file.relativePath, fileImports, changedPaths, resolver)) {
|
|
7622
8085
|
keep.add(file.relativePath);
|
|
7623
8086
|
}
|
|
7624
8087
|
}
|
|
@@ -7649,6 +8112,9 @@ function generateSnapshot(configInput, options) {
|
|
|
7649
8112
|
for (const path14 of [...monolithBodies.keys()]) {
|
|
7650
8113
|
if (!keep.has(path14)) monolithBodies.delete(path14);
|
|
7651
8114
|
}
|
|
8115
|
+
for (const path14 of [...skippedSummaryImports.keys()]) {
|
|
8116
|
+
if (!keep.has(path14)) skippedSummaryImports.delete(path14);
|
|
8117
|
+
}
|
|
7652
8118
|
}
|
|
7653
8119
|
if (changedScope !== null) {
|
|
7654
8120
|
for (const relativePath of unchangedPaths) {
|
|
@@ -7684,7 +8150,7 @@ function generateSnapshot(configInput, options) {
|
|
|
7684
8150
|
const shown = oversizeSummaryPaths.slice(0, ENCODING_PATHS_SHOWN).map((entry) => maskPathText(entry, config.secretRules));
|
|
7685
8151
|
const hidden = oversizeSummaryPaths.length - ENCODING_PATHS_SHOWN;
|
|
7686
8152
|
warnings.push(
|
|
7687
|
-
`${oversizeSummaryPaths.length} file(s) exceed ${Math.round(
|
|
8153
|
+
`${oversizeSummaryPaths.length} file(s) exceed ${Math.round(SUMMARY_MAX_SOURCE_BYTES2 / (1024 * 1024))} MB and were not parsed for a structural summary: ${shown.join(", ")}${hidden > 0 ? ` and ${hidden} more` : ""}. Their bodies are emitted as head/tail previews.`
|
|
7688
8154
|
);
|
|
7689
8155
|
}
|
|
7690
8156
|
for (const [encoding, bucket] of encodingBuckets) {
|
|
@@ -7708,11 +8174,13 @@ function generateSnapshot(configInput, options) {
|
|
|
7708
8174
|
).join("\n")
|
|
7709
8175
|
);
|
|
7710
8176
|
const fullContents = /* @__PURE__ */ new Map();
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
|
|
7714
|
-
|
|
7715
|
-
|
|
8177
|
+
if (config.includeMonolith) {
|
|
8178
|
+
for (const file of files) {
|
|
8179
|
+
fullContents.set(
|
|
8180
|
+
file.relativePath,
|
|
8181
|
+
monolithBodies.get(file.relativePath) ?? file.content ?? ""
|
|
8182
|
+
);
|
|
8183
|
+
}
|
|
7716
8184
|
}
|
|
7717
8185
|
const parts = partitionByBudget(files, config, fingerprint);
|
|
7718
8186
|
const truncatedPreviewCount = files.filter((file) => file.isPreviewTruncated).length;
|
|
@@ -8051,12 +8519,35 @@ async function openWorkspace(root, overrides = {}) {
|
|
|
8051
8519
|
}
|
|
8052
8520
|
cliOptions.maxPartBytes = parsed;
|
|
8053
8521
|
}
|
|
8522
|
+
if (overrides.maxPartTokens !== void 0) {
|
|
8523
|
+
const parsed = parseByteSize(overrides.maxPartTokens);
|
|
8524
|
+
if (parsed === void 0) {
|
|
8525
|
+
return {
|
|
8526
|
+
ok: false,
|
|
8527
|
+
message: '"maxPartTokens" must be a token count, for example 32000 or "32k".'
|
|
8528
|
+
};
|
|
8529
|
+
}
|
|
8530
|
+
cliOptions.maxPartTokens = parsed;
|
|
8531
|
+
}
|
|
8054
8532
|
if (overrides.outDir !== void 0) {
|
|
8055
8533
|
if (typeof overrides.outDir !== "string" || overrides.outDir.trim().length === 0) {
|
|
8056
8534
|
return { ok: false, message: '"outDir" must be a non-empty string.' };
|
|
8057
8535
|
}
|
|
8058
8536
|
cliOptions.outDir = overrides.outDir.trim();
|
|
8059
8537
|
}
|
|
8538
|
+
if (overrides.changedSince !== void 0) {
|
|
8539
|
+
if (typeof overrides.changedSince !== "string" || overrides.changedSince.trim().length === 0) {
|
|
8540
|
+
return {
|
|
8541
|
+
ok: false,
|
|
8542
|
+
message: '"changedSince" must be a git ref such as "main" or "HEAD~3".'
|
|
8543
|
+
};
|
|
8544
|
+
}
|
|
8545
|
+
cliOptions.changedSince = overrides.changedSince.trim();
|
|
8546
|
+
}
|
|
8547
|
+
if (overrides.skeleton === true) cliOptions.skeleton = true;
|
|
8548
|
+
if (overrides.sarif === true) cliOptions.sarif = true;
|
|
8549
|
+
if (overrides.staged === true) cliOptions.staged = true;
|
|
8550
|
+
if (overrides.withDependents === true) cliOptions.withDependents = true;
|
|
8060
8551
|
try {
|
|
8061
8552
|
const config = resolveConfig(loaded.config, cliOptions, root);
|
|
8062
8553
|
return { ok: true, workspace: { root, config, configFile: loaded.file, cliOptions } };
|
|
@@ -8068,6 +8559,16 @@ var manifestCache = /* @__PURE__ */ new Map();
|
|
|
8068
8559
|
function manifestPathFor(workspace) {
|
|
8069
8560
|
return path10__namespace.resolve(workspace.root, workspace.config.outDir, "manifest.json");
|
|
8070
8561
|
}
|
|
8562
|
+
function partPathFor(workspace, filename) {
|
|
8563
|
+
if (filename.length === 0 || filename.includes("\0")) return null;
|
|
8564
|
+
const partsDir = path10__namespace.resolve(workspace.root, workspace.config.outDir, "parts");
|
|
8565
|
+
const resolved = path10__namespace.resolve(partsDir, filename);
|
|
8566
|
+
const relative8 = path10__namespace.relative(partsDir, resolved);
|
|
8567
|
+
if (relative8.length === 0 || relative8.includes(path10__namespace.sep) || relative8.includes("/") || relative8.includes("\\") || path10__namespace.isAbsolute(relative8)) {
|
|
8568
|
+
return null;
|
|
8569
|
+
}
|
|
8570
|
+
return resolved;
|
|
8571
|
+
}
|
|
8071
8572
|
function readManifest3(workspace) {
|
|
8072
8573
|
const file = manifestPathFor(workspace);
|
|
8073
8574
|
const shown = path10__namespace.relative(workspace.root, file).split(path10__namespace.sep).join("/") || file;
|
|
@@ -8138,6 +8639,44 @@ var OUT_DIR_PROPERTY = {
|
|
|
8138
8639
|
description: "Snapshot directory, relative to the root. Defaults to the project configuration's outDir."
|
|
8139
8640
|
};
|
|
8140
8641
|
var outDirOverride = (args) => ({ outDir: args.outDir });
|
|
8642
|
+
var SCOPE_PROPERTIES = {
|
|
8643
|
+
maxPartTokens: {
|
|
8644
|
+
type: "string",
|
|
8645
|
+
description: 'Token ceiling per part, for example 32000 or "32k". Narrower than maxPartBytes; it converts at four bytes per token.'
|
|
8646
|
+
},
|
|
8647
|
+
skeleton: {
|
|
8648
|
+
type: "boolean",
|
|
8649
|
+
description: "Replace every function body with `{ /* ... */ }`, keeping signatures, imports and exports. Applies to TypeScript, JavaScript and JSX."
|
|
8650
|
+
},
|
|
8651
|
+
sarif: {
|
|
8652
|
+
type: "boolean",
|
|
8653
|
+
description: "Also write reports/audit.sarif beside reports/audit.md, for CI code scanning."
|
|
8654
|
+
},
|
|
8655
|
+
changedSince: {
|
|
8656
|
+
type: "string",
|
|
8657
|
+
description: 'Only files changed since this git ref, for example "main" or "HEAD~3".'
|
|
8658
|
+
},
|
|
8659
|
+
staged: {
|
|
8660
|
+
type: "boolean",
|
|
8661
|
+
description: "Only files staged in the git index."
|
|
8662
|
+
},
|
|
8663
|
+
withDependents: {
|
|
8664
|
+
type: "boolean",
|
|
8665
|
+
description: "With staged or changedSince, also include the files that import the changed ones (one hop)."
|
|
8666
|
+
}
|
|
8667
|
+
};
|
|
8668
|
+
function workspaceOverrides(args) {
|
|
8669
|
+
return {
|
|
8670
|
+
outDir: args.outDir,
|
|
8671
|
+
maxPartBytes: args.maxPartBytes,
|
|
8672
|
+
maxPartTokens: args.maxPartTokens,
|
|
8673
|
+
skeleton: args.skeleton,
|
|
8674
|
+
sarif: args.sarif,
|
|
8675
|
+
changedSince: args.changedSince,
|
|
8676
|
+
staged: args.staged,
|
|
8677
|
+
withDependents: args.withDependents
|
|
8678
|
+
};
|
|
8679
|
+
}
|
|
8141
8680
|
function failure(message) {
|
|
8142
8681
|
return { text: message, isError: true };
|
|
8143
8682
|
}
|
|
@@ -8168,12 +8707,13 @@ function summarizeDrift(drift) {
|
|
|
8168
8707
|
}
|
|
8169
8708
|
function toRelativePath(root, value) {
|
|
8170
8709
|
const cleaned = value.trim();
|
|
8171
|
-
if (cleaned.length === 0) return null;
|
|
8172
|
-
|
|
8173
|
-
|
|
8710
|
+
if (cleaned.length === 0 || cleaned.includes("\0")) return null;
|
|
8711
|
+
const resolvedRoot = path10__namespace.resolve(root);
|
|
8712
|
+
const absolute = path10__namespace.resolve(resolvedRoot, cleaned);
|
|
8713
|
+
const relative8 = path10__namespace.relative(resolvedRoot, absolute);
|
|
8714
|
+
if (relative8 === "" || relative8 === ".." || relative8.startsWith(`..${path10__namespace.sep}`) || path10__namespace.isAbsolute(relative8)) {
|
|
8715
|
+
return null;
|
|
8174
8716
|
}
|
|
8175
|
-
const relative8 = path10__namespace.relative(root, cleaned);
|
|
8176
|
-
if (relative8.startsWith("..") || path10__namespace.isAbsolute(relative8)) return null;
|
|
8177
8717
|
return relative8.split(path10__namespace.sep).join("/");
|
|
8178
8718
|
}
|
|
8179
8719
|
function symbolsOf(entry) {
|
|
@@ -8309,7 +8849,8 @@ var planTool = {
|
|
|
8309
8849
|
maxPartBytes: {
|
|
8310
8850
|
type: "string",
|
|
8311
8851
|
description: 'Byte budget per part, for example 307200 or "300k". Defaults to the project configuration.'
|
|
8312
|
-
}
|
|
8852
|
+
},
|
|
8853
|
+
...SCOPE_PROPERTIES
|
|
8313
8854
|
},
|
|
8314
8855
|
additionalProperties: false
|
|
8315
8856
|
},
|
|
@@ -8326,7 +8867,7 @@ var planTool = {
|
|
|
8326
8867
|
},
|
|
8327
8868
|
annotations: READ_ONLY,
|
|
8328
8869
|
async handler(args, context) {
|
|
8329
|
-
const prepared = await prepare(args, context,
|
|
8870
|
+
const prepared = await prepare(args, context, workspaceOverrides(args));
|
|
8330
8871
|
if (!prepared.ok) return prepared.outcome;
|
|
8331
8872
|
const workspace = prepared.workspace;
|
|
8332
8873
|
let manifest;
|
|
@@ -8384,7 +8925,8 @@ var generateTool = {
|
|
|
8384
8925
|
maxPartBytes: {
|
|
8385
8926
|
type: "string",
|
|
8386
8927
|
description: 'Byte budget per part, for example 307200 or "300k". Defaults to the project configuration.'
|
|
8387
|
-
}
|
|
8928
|
+
},
|
|
8929
|
+
...SCOPE_PROPERTIES
|
|
8388
8930
|
},
|
|
8389
8931
|
additionalProperties: false
|
|
8390
8932
|
},
|
|
@@ -8400,10 +8942,7 @@ var generateTool = {
|
|
|
8400
8942
|
},
|
|
8401
8943
|
annotations: WRITES,
|
|
8402
8944
|
async handler(args, context) {
|
|
8403
|
-
const prepared = await prepare(args, context,
|
|
8404
|
-
maxPartBytes: args.maxPartBytes,
|
|
8405
|
-
outDir: args.outDir
|
|
8406
|
-
});
|
|
8945
|
+
const prepared = await prepare(args, context, workspaceOverrides(args));
|
|
8407
8946
|
if (!prepared.ok) return prepared.outcome;
|
|
8408
8947
|
const workspace = prepared.workspace;
|
|
8409
8948
|
const result = await generateInWorker(workspace.root, workspace.cliOptions);
|
|
@@ -8442,7 +8981,7 @@ var validateTool = {
|
|
|
8442
8981
|
description: "Re-read the repository and report whether the snapshot on disk still matches it. Use it before trusting context that came from an earlier session, or after changing the config.",
|
|
8443
8982
|
inputSchema: {
|
|
8444
8983
|
type: "object",
|
|
8445
|
-
properties: { root: ROOT_PROPERTY, outDir: OUT_DIR_PROPERTY },
|
|
8984
|
+
properties: { root: ROOT_PROPERTY, outDir: OUT_DIR_PROPERTY, ...SCOPE_PROPERTIES },
|
|
8446
8985
|
additionalProperties: false
|
|
8447
8986
|
},
|
|
8448
8987
|
outputSchema: {
|
|
@@ -8454,7 +8993,7 @@ var validateTool = {
|
|
|
8454
8993
|
},
|
|
8455
8994
|
annotations: READ_ONLY,
|
|
8456
8995
|
async handler(args, context) {
|
|
8457
|
-
const prepared = await prepare(args, context,
|
|
8996
|
+
const prepared = await prepare(args, context, workspaceOverrides(args));
|
|
8458
8997
|
if (!prepared.ok) return prepared.outcome;
|
|
8459
8998
|
const workspace = prepared.workspace;
|
|
8460
8999
|
let result;
|
|
@@ -8799,7 +9338,12 @@ var readTool = {
|
|
|
8799
9338
|
`${relativePath} is not in the snapshot. Call snapshot_locate to find the path, or snapshot_explain to learn why it was excluded.`
|
|
8800
9339
|
);
|
|
8801
9340
|
}
|
|
8802
|
-
const partPath =
|
|
9341
|
+
const partPath = partPathFor(workspace, entry.part);
|
|
9342
|
+
if (partPath === null) {
|
|
9343
|
+
return failure(
|
|
9344
|
+
`${entry.part} is not a part of this snapshot: its name leaves ${workspace.config.outDir}/parts. Run snapshot_generate to rebuild it.`
|
|
9345
|
+
);
|
|
9346
|
+
}
|
|
8803
9347
|
let partText;
|
|
8804
9348
|
try {
|
|
8805
9349
|
partText = fs8__namespace.readFileSync(partPath, "utf8");
|
|
@@ -8879,7 +9423,8 @@ var explainTool = {
|
|
|
8879
9423
|
description: "Path relative to the repository root. Directories are explained as a whole."
|
|
8880
9424
|
},
|
|
8881
9425
|
root: ROOT_PROPERTY,
|
|
8882
|
-
outDir: OUT_DIR_PROPERTY
|
|
9426
|
+
outDir: OUT_DIR_PROPERTY,
|
|
9427
|
+
...SCOPE_PROPERTIES
|
|
8883
9428
|
},
|
|
8884
9429
|
required: ["path"],
|
|
8885
9430
|
additionalProperties: false
|
|
@@ -8894,7 +9439,7 @@ var explainTool = {
|
|
|
8894
9439
|
},
|
|
8895
9440
|
annotations: READ_ONLY,
|
|
8896
9441
|
async handler(args, context) {
|
|
8897
|
-
const prepared = await prepare(args, context,
|
|
9442
|
+
const prepared = await prepare(args, context, workspaceOverrides(args));
|
|
8898
9443
|
if (!prepared.ok) return prepared.outcome;
|
|
8899
9444
|
const workspace = prepared.workspace;
|
|
8900
9445
|
if (typeof args.path !== "string") return failure('"path" must be a string.');
|
|
@@ -9607,7 +10152,7 @@ function buildAgentContract() {
|
|
|
9607
10152
|
{ key: "preset", type: "string", default: "detected", summary: "Force a preset. Unknown names are an error." },
|
|
9608
10153
|
{ key: "maxPartBytes", type: "number | string", default: 307200, summary: "Per-part byte budget." },
|
|
9609
10154
|
{ key: "maxPartTokens", type: "number | string | null", default: null, summary: "Per-part token ceiling; narrows maxPartBytes. Minimum 1024." },
|
|
9610
|
-
{ key: "skeleton", type: "boolean", default: false, summary: "Collapse function bodies to `{ /* ... */ }` in
|
|
10155
|
+
{ key: "skeleton", type: "boolean", default: false, summary: "Collapse function bodies to `{ /* ... */ }` in TS, JS, TSX and JSX files." },
|
|
9611
10156
|
{ key: "sarif", type: "boolean", default: false, summary: "Also write reports/audit.sarif." },
|
|
9612
10157
|
{ key: "changedSince", type: "string | null", default: null, summary: "Snapshot only files that differ from this git ref." },
|
|
9613
10158
|
{ key: "staged", type: "boolean", default: false, summary: "Snapshot only files staged in the index." },
|
|
@@ -9998,9 +10543,9 @@ function buildResourceProvider() {
|
|
|
9998
10543
|
const index = Number(partMatch[1]);
|
|
9999
10544
|
const part = read.manifest.parts.find((candidate) => candidate.index === index);
|
|
10000
10545
|
if (!part) return null;
|
|
10001
|
-
const
|
|
10002
|
-
|
|
10003
|
-
);
|
|
10546
|
+
const partPath = partPathFor(workspace, part.filename);
|
|
10547
|
+
if (partPath === null) return null;
|
|
10548
|
+
const text = readFileIfPresent(partPath);
|
|
10004
10549
|
if (text === null) return null;
|
|
10005
10550
|
return { uri, mimeType: "text/markdown", text: capUtf8(text, MAX_RESOURCE_BYTES).text };
|
|
10006
10551
|
}
|
|
@@ -10032,11 +10577,11 @@ var MAX_LINE_BYTES = 32 * 1024 * 1024;
|
|
|
10032
10577
|
function createWriter(output) {
|
|
10033
10578
|
return {
|
|
10034
10579
|
write(value) {
|
|
10035
|
-
return new Promise((
|
|
10580
|
+
return new Promise((resolve9, reject) => {
|
|
10036
10581
|
output.write(`${JSON.stringify(value)}
|
|
10037
10582
|
`, (error) => {
|
|
10038
10583
|
if (error) reject(error);
|
|
10039
|
-
else
|
|
10584
|
+
else resolve9();
|
|
10040
10585
|
});
|
|
10041
10586
|
});
|
|
10042
10587
|
}
|
|
@@ -10044,6 +10589,7 @@ function createWriter(output) {
|
|
|
10044
10589
|
}
|
|
10045
10590
|
function createLineReader(input, options) {
|
|
10046
10591
|
let buffer = "";
|
|
10592
|
+
let bufferBytes = 0;
|
|
10047
10593
|
let discarding = false;
|
|
10048
10594
|
let discardedBytes = 0;
|
|
10049
10595
|
const deliver = (line) => {
|
|
@@ -10056,6 +10602,13 @@ function createLineReader(input, options) {
|
|
|
10056
10602
|
if (trimmed.trim().length === 0) return;
|
|
10057
10603
|
options.onLine(trimmed);
|
|
10058
10604
|
};
|
|
10605
|
+
const discardBuffered = () => {
|
|
10606
|
+
discarding = true;
|
|
10607
|
+
discardedBytes += bufferBytes;
|
|
10608
|
+
buffer = "";
|
|
10609
|
+
bufferBytes = 0;
|
|
10610
|
+
options.onOverflow?.(discardedBytes);
|
|
10611
|
+
};
|
|
10059
10612
|
const drain = () => {
|
|
10060
10613
|
let index = buffer.indexOf("\n");
|
|
10061
10614
|
while (index >= 0) {
|
|
@@ -10063,42 +10616,57 @@ function createLineReader(input, options) {
|
|
|
10063
10616
|
buffer = buffer.slice(index + 1);
|
|
10064
10617
|
if (discarding) {
|
|
10065
10618
|
deliver(line);
|
|
10066
|
-
} else if (line.length > MAX_LINE_BYTES) {
|
|
10067
|
-
options.onOverflow?.(line.length);
|
|
10068
10619
|
} else {
|
|
10069
|
-
|
|
10620
|
+
const lineBytes = Buffer.byteLength(line, "utf8");
|
|
10621
|
+
if (lineBytes > MAX_LINE_BYTES) options.onOverflow?.(lineBytes);
|
|
10622
|
+
else deliver(line);
|
|
10070
10623
|
}
|
|
10071
10624
|
index = buffer.indexOf("\n");
|
|
10072
10625
|
}
|
|
10626
|
+
bufferBytes = Buffer.byteLength(buffer, "utf8");
|
|
10627
|
+
if (!discarding && bufferBytes > MAX_LINE_BYTES) discardBuffered();
|
|
10073
10628
|
};
|
|
10074
10629
|
const onData = (chunk) => {
|
|
10630
|
+
const chunkBytes = Buffer.byteLength(chunk, "utf8");
|
|
10075
10631
|
if (discarding) {
|
|
10076
10632
|
const index = chunk.indexOf("\n");
|
|
10077
10633
|
if (index < 0) {
|
|
10078
|
-
discardedBytes +=
|
|
10634
|
+
discardedBytes += chunkBytes;
|
|
10079
10635
|
return;
|
|
10080
10636
|
}
|
|
10081
10637
|
buffer = chunk.slice(index + 1);
|
|
10638
|
+
bufferBytes = Buffer.byteLength(buffer, "utf8");
|
|
10082
10639
|
deliver("");
|
|
10083
10640
|
drain();
|
|
10084
10641
|
return;
|
|
10085
10642
|
}
|
|
10086
|
-
|
|
10087
|
-
drain();
|
|
10088
|
-
if (buffer.length > MAX_LINE_BYTES) {
|
|
10643
|
+
if (chunk.indexOf("\n") < 0 && bufferBytes + chunkBytes > MAX_LINE_BYTES) {
|
|
10089
10644
|
discarding = true;
|
|
10090
|
-
discardedBytes =
|
|
10645
|
+
discardedBytes = bufferBytes + chunkBytes;
|
|
10091
10646
|
buffer = "";
|
|
10647
|
+
bufferBytes = 0;
|
|
10092
10648
|
options.onOverflow?.(discardedBytes);
|
|
10093
10649
|
return;
|
|
10094
10650
|
}
|
|
10651
|
+
buffer += chunk;
|
|
10652
|
+
drain();
|
|
10095
10653
|
};
|
|
10096
10654
|
const onEnd = () => {
|
|
10097
|
-
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
|
|
10655
|
+
const rest = buffer;
|
|
10656
|
+
const restBytes = bufferBytes || Buffer.byteLength(rest, "utf8");
|
|
10657
|
+
buffer = "";
|
|
10658
|
+
bufferBytes = 0;
|
|
10659
|
+
if (rest.length === 0) return;
|
|
10660
|
+
if (discarding) {
|
|
10661
|
+
discarding = false;
|
|
10662
|
+
discardedBytes = 0;
|
|
10663
|
+
return;
|
|
10664
|
+
}
|
|
10665
|
+
if (restBytes > MAX_LINE_BYTES) {
|
|
10666
|
+
options.onOverflow?.(restBytes);
|
|
10667
|
+
return;
|
|
10101
10668
|
}
|
|
10669
|
+
deliver(rest);
|
|
10102
10670
|
};
|
|
10103
10671
|
input.setEncoding("utf8");
|
|
10104
10672
|
input.on("data", onData);
|
|
@@ -10149,8 +10717,8 @@ async function runStdioServer(options) {
|
|
|
10149
10717
|
let inFlight = 0;
|
|
10150
10718
|
let inputEnded = false;
|
|
10151
10719
|
let resolveDone = () => void 0;
|
|
10152
|
-
const finished = new Promise((
|
|
10153
|
-
resolveDone =
|
|
10720
|
+
const finished = new Promise((resolve9) => {
|
|
10721
|
+
resolveDone = resolve9;
|
|
10154
10722
|
});
|
|
10155
10723
|
const finishIfIdle = () => {
|
|
10156
10724
|
if (inputEnded && inFlight === 0) resolveDone(0);
|