@lzehrung/codegraph 3.1.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/codegraph-skill/codegraph/SKILL.md +3 -2
- package/dist/agent/explain.d.ts.map +1 -1
- package/dist/agent/explain.js +12 -7
- package/dist/agent/explain.js.map +1 -1
- package/dist/agent/search.d.ts +13 -0
- package/dist/agent/search.d.ts.map +1 -1
- package/dist/agent/search.js +10 -4
- package/dist/agent/search.js.map +1 -1
- package/dist/bin/cli.js +1644 -675
- package/dist/cli/command-table.d.ts.map +1 -1
- package/dist/cli/command-table.js +4 -0
- package/dist/cli/command-table.js.map +1 -1
- package/dist/cli/duplicates.d.ts +5 -0
- package/dist/cli/duplicates.d.ts.map +1 -1
- package/dist/cli/duplicates.js +15 -2
- package/dist/cli/duplicates.js.map +1 -1
- package/dist/cli/help.d.ts +4 -4
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +15 -9
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +4 -0
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/options.d.ts.map +1 -1
- package/dist/cli/options.js +5 -1
- package/dist/cli/options.js.map +1 -1
- package/dist/cli/progress.d.ts.map +1 -1
- package/dist/cli/progress.js +42 -16
- package/dist/cli/progress.js.map +1 -1
- package/dist/cli/server.d.ts.map +1 -1
- package/dist/cli/server.js +2 -0
- package/dist/cli/server.js.map +1 -1
- package/dist/cli/viewer.js +1 -1
- package/dist/cli/viewer.js.map +1 -1
- package/dist/drift/git.d.ts.map +1 -1
- package/dist/drift/git.js +10 -2
- package/dist/drift/git.js.map +1 -1
- package/dist/duplicates/candidates.d.ts +61 -0
- package/dist/duplicates/candidates.d.ts.map +1 -0
- package/dist/duplicates/candidates.js +873 -0
- package/dist/duplicates/candidates.js.map +1 -0
- package/dist/duplicates/progress.d.ts +17 -0
- package/dist/duplicates/progress.d.ts.map +1 -0
- package/dist/duplicates/progress.js +57 -0
- package/dist/duplicates/progress.js.map +1 -0
- package/dist/duplicates/scoring.d.ts +9 -40
- package/dist/duplicates/scoring.d.ts.map +1 -1
- package/dist/duplicates/scoring.js +34 -414
- package/dist/duplicates/scoring.js.map +1 -1
- package/dist/duplicates/types.d.ts +30 -1
- package/dist/duplicates/types.d.ts.map +1 -1
- package/dist/duplicates/units.d.ts +2 -1
- package/dist/duplicates/units.d.ts.map +1 -1
- package/dist/duplicates/units.js +24 -3
- package/dist/duplicates/units.js.map +1 -1
- package/dist/duplicates.d.ts +1 -0
- package/dist/duplicates.d.ts.map +1 -1
- package/dist/duplicates.js +116 -62
- package/dist/duplicates.js.map +1 -1
- package/dist/impact/providers/base.js +1 -1
- package/dist/impact/providers/base.js.map +1 -1
- package/dist/mcp/cancellation.d.ts +6 -0
- package/dist/mcp/cancellation.d.ts.map +1 -0
- package/dist/mcp/cancellation.js +11 -0
- package/dist/mcp/cancellation.js.map +1 -0
- package/dist/mcp/handlers.d.ts +33 -3
- package/dist/mcp/handlers.d.ts.map +1 -1
- package/dist/mcp/handlers.js +128 -30
- package/dist/mcp/handlers.js.map +1 -1
- package/dist/mcp/http-transport.d.ts.map +1 -1
- package/dist/mcp/http-transport.js +7 -4
- package/dist/mcp/http-transport.js.map +1 -1
- package/dist/mcp/index-readiness.d.ts +114 -0
- package/dist/mcp/index-readiness.d.ts.map +1 -0
- package/dist/mcp/index-readiness.js +264 -0
- package/dist/mcp/index-readiness.js.map +1 -0
- package/dist/mcp/protocol.d.ts.map +1 -1
- package/dist/mcp/protocol.js +23 -10
- package/dist/mcp/protocol.js.map +1 -1
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +9 -4
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/stale-install.d.ts +13 -0
- package/dist/mcp/stale-install.d.ts.map +1 -0
- package/dist/mcp/stale-install.js +30 -0
- package/dist/mcp/stale-install.js.map +1 -0
- package/dist/review/deleted.js +1 -1
- package/dist/review/deleted.js.map +1 -1
- package/dist/review.d.ts +6 -0
- package/dist/review.d.ts.map +1 -1
- package/dist/review.js +1 -1
- package/dist/review.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/util/concurrency.d.ts +7 -0
- package/dist/util/concurrency.d.ts.map +1 -1
- package/dist/util/concurrency.js +11 -0
- package/dist/util/concurrency.js.map +1 -1
- package/docs/mcp.md +56 -7
- package/package.json +3 -3
package/dist/bin/cli.js
CHANGED
|
@@ -685,6 +685,7 @@ var init_options = __esm({
|
|
|
685
685
|
"--min-tokens",
|
|
686
686
|
"--max-tokens",
|
|
687
687
|
"--max-bucket-size",
|
|
688
|
+
"--max-candidate-pairs",
|
|
688
689
|
"--min-confidence",
|
|
689
690
|
"--max-hits",
|
|
690
691
|
"--resolution-hint",
|
|
@@ -722,6 +723,7 @@ var init_options = __esm({
|
|
|
722
723
|
"--graph",
|
|
723
724
|
"--port",
|
|
724
725
|
"--idle-timeout-ms",
|
|
726
|
+
"--index-wait-ms",
|
|
725
727
|
"--startup-timeout-ms",
|
|
726
728
|
"--offset",
|
|
727
729
|
"--max-bytes",
|
|
@@ -848,6 +850,7 @@ var init_options = __esm({
|
|
|
848
850
|
"--include-root-glob",
|
|
849
851
|
"--limit",
|
|
850
852
|
"--max-bucket-size",
|
|
853
|
+
"--max-candidate-pairs",
|
|
851
854
|
"--max-tokens",
|
|
852
855
|
"--min-confidence",
|
|
853
856
|
"--min-tokens",
|
|
@@ -994,7 +997,7 @@ var init_options = __esm({
|
|
|
994
997
|
],
|
|
995
998
|
[
|
|
996
999
|
"mcp",
|
|
997
|
-
commandSchema([...SHARED_BUILD_FLAGS, "--allow-build", "--stdio", "--warmup", "--warmup-symbols", "--no-warmup", "--no-watch"], [...SHARED_BUILD_OPTIONS, "--artifact", "--host", "--port", "--idle-timeout-ms"], {
|
|
1000
|
+
commandSchema([...SHARED_BUILD_FLAGS, "--allow-build", "--stdio", "--warmup", "--warmup-symbols", "--no-warmup", "--no-watch"], [...SHARED_BUILD_OPTIONS, "--artifact", "--host", "--port", "--idle-timeout-ms", "--index-wait-ms"], {
|
|
998
1001
|
kind: "max",
|
|
999
1002
|
max: 1,
|
|
1000
1003
|
usage: "Usage: codegraph mcp [serve] [--root <path>] [--stdio | --port <number>]"
|
|
@@ -1019,6 +1022,7 @@ var init_options = __esm({
|
|
|
1019
1022
|
"--host",
|
|
1020
1023
|
"--ignore-glob",
|
|
1021
1024
|
"--include-glob",
|
|
1025
|
+
"--index-wait-ms",
|
|
1022
1026
|
"--port",
|
|
1023
1027
|
"--resolution-hint",
|
|
1024
1028
|
"--root",
|
|
@@ -1237,6 +1241,7 @@ function createInteractiveProgressDisplay(write, delayMs = 0) {
|
|
|
1237
1241
|
let current = 0;
|
|
1238
1242
|
let total = 0;
|
|
1239
1243
|
let mode = "build";
|
|
1244
|
+
let unit = DEFAULT_COUNT_UNIT;
|
|
1240
1245
|
let activity = progressAction(mode);
|
|
1241
1246
|
let interval;
|
|
1242
1247
|
let delay3;
|
|
@@ -1252,7 +1257,7 @@ function createInteractiveProgressDisplay(write, delayMs = 0) {
|
|
|
1252
1257
|
return;
|
|
1253
1258
|
const frame = SPINNER_FRAMES[frameIndex % SPINNER_FRAMES.length];
|
|
1254
1259
|
frameIndex += 1;
|
|
1255
|
-
const count = hasProgressCount(mode, current, total) ? formatProgressCount(current, total) : "";
|
|
1260
|
+
const count = hasProgressCount(mode, current, total) ? formatProgressCount(current, total, unit) : "";
|
|
1256
1261
|
const elapsed = ` (${formatDuration(performance2.now() - phaseStartedAt)})`;
|
|
1257
1262
|
write(`${CLEAR_LINE}${activity}... ${frame}${count}${elapsed}`);
|
|
1258
1263
|
rendered = true;
|
|
@@ -1276,6 +1281,7 @@ function createInteractiveProgressDisplay(write, delayMs = 0) {
|
|
|
1276
1281
|
current = update.current;
|
|
1277
1282
|
total = update.total;
|
|
1278
1283
|
mode = update.mode ?? "build";
|
|
1284
|
+
unit = update.unit ?? DEFAULT_COUNT_UNIT;
|
|
1279
1285
|
activity = update.activity ?? `${progressAction(mode)} project index`;
|
|
1280
1286
|
phaseStartedAt = performance2.now();
|
|
1281
1287
|
const beginRendering = () => {
|
|
@@ -1300,10 +1306,14 @@ function createInteractiveProgressDisplay(write, delayMs = 0) {
|
|
|
1300
1306
|
if (!rendered)
|
|
1301
1307
|
return;
|
|
1302
1308
|
clear();
|
|
1303
|
-
const verb = progressCompleteVerb(update.mode ?? mode);
|
|
1304
|
-
const fileCount = formatFileCount(update.total, "words");
|
|
1305
1309
|
const elapsed = update.elapsedMs === void 0 ? "" : ` in ${formatDuration(update.elapsedMs)}`;
|
|
1306
|
-
|
|
1310
|
+
if (update.activity !== void 0) {
|
|
1311
|
+
write(`${update.activity}: ${formatCount(update.total, update.unit ?? DEFAULT_COUNT_UNIT, "words")}${elapsed}.
|
|
1312
|
+
`);
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
const verb = progressCompleteVerb(update.mode ?? mode);
|
|
1316
|
+
write(`${verb} project index: ${formatCount(update.total, DEFAULT_COUNT_UNIT, "words")}${elapsed}.
|
|
1307
1317
|
`);
|
|
1308
1318
|
};
|
|
1309
1319
|
return {
|
|
@@ -1324,10 +1334,17 @@ function createInteractiveProgressDisplay(write, delayMs = 0) {
|
|
|
1324
1334
|
current = update.current;
|
|
1325
1335
|
total = update.total;
|
|
1326
1336
|
mode = update.mode ?? mode;
|
|
1327
|
-
if (update.activity !== void 0
|
|
1337
|
+
if (update.activity !== void 0)
|
|
1338
|
+
unit = update.unit ?? DEFAULT_COUNT_UNIT;
|
|
1339
|
+
else if (update.unit !== void 0)
|
|
1340
|
+
unit = update.unit;
|
|
1341
|
+
const activityChanged = update.activity !== void 0 && update.activity !== activity;
|
|
1342
|
+
if (activityChanged)
|
|
1328
1343
|
phaseStartedAt = performance2.now();
|
|
1329
1344
|
if (update.activity !== void 0)
|
|
1330
1345
|
activity = update.activity;
|
|
1346
|
+
if (activityChanged && interval !== void 0)
|
|
1347
|
+
render();
|
|
1331
1348
|
},
|
|
1332
1349
|
clear,
|
|
1333
1350
|
dispose: () => {
|
|
@@ -1337,15 +1354,15 @@ function createInteractiveProgressDisplay(write, delayMs = 0) {
|
|
|
1337
1354
|
}
|
|
1338
1355
|
};
|
|
1339
1356
|
}
|
|
1340
|
-
function
|
|
1357
|
+
function formatCount(count, unit, zeroFormat = "numeric") {
|
|
1341
1358
|
if (!count && zeroFormat === "words")
|
|
1342
|
-
return
|
|
1343
|
-
return `${count}
|
|
1359
|
+
return `no ${unit}s`;
|
|
1360
|
+
return `${count} ${unit}${count === 1 ? "" : "s"}`;
|
|
1344
1361
|
}
|
|
1345
|
-
function formatProgressCount(current, total) {
|
|
1362
|
+
function formatProgressCount(current, total, unit) {
|
|
1346
1363
|
if (total > 0)
|
|
1347
|
-
return ` ${current}/${
|
|
1348
|
-
return ` ${
|
|
1364
|
+
return ` ${current}/${formatCount(total, unit)}`;
|
|
1365
|
+
return ` ${formatCount(current, unit)} processed`;
|
|
1349
1366
|
}
|
|
1350
1367
|
function hasProgressCount(mode, current, total) {
|
|
1351
1368
|
return mode !== "check" || current > 0 || total > 0;
|
|
@@ -1356,6 +1373,7 @@ function createLogProgressDisplay(write, delayMs = 0) {
|
|
|
1356
1373
|
let current = 0;
|
|
1357
1374
|
let total = 0;
|
|
1358
1375
|
let mode = "build";
|
|
1376
|
+
let unit = DEFAULT_COUNT_UNIT;
|
|
1359
1377
|
let activity = progressAction(mode);
|
|
1360
1378
|
let delay3;
|
|
1361
1379
|
let heartbeat;
|
|
@@ -1379,7 +1397,7 @@ function createLogProgressDisplay(write, delayMs = 0) {
|
|
|
1379
1397
|
heartbeat = setInterval(() => {
|
|
1380
1398
|
if (!active)
|
|
1381
1399
|
return;
|
|
1382
|
-
const count = hasProgressCount(mode, current, total) ? `:${formatProgressCount(current, total)}` : "";
|
|
1400
|
+
const count = hasProgressCount(mode, current, total) ? `:${formatProgressCount(current, total, unit)}` : "";
|
|
1383
1401
|
const elapsed = formatDuration(performance2.now() - phaseStartedAt);
|
|
1384
1402
|
write(`[Progress] ${activity}${count}. (${elapsed})
|
|
1385
1403
|
`);
|
|
@@ -1393,6 +1411,7 @@ function createLogProgressDisplay(write, delayMs = 0) {
|
|
|
1393
1411
|
current = update.current;
|
|
1394
1412
|
total = update.total;
|
|
1395
1413
|
mode = update.mode ?? "build";
|
|
1414
|
+
unit = update.unit ?? DEFAULT_COUNT_UNIT;
|
|
1396
1415
|
activity = update.activity ?? `${progressAction(mode)} project index`;
|
|
1397
1416
|
phaseStartedAt = performance2.now();
|
|
1398
1417
|
if (delayMs) {
|
|
@@ -1415,9 +1434,14 @@ function createLogProgressDisplay(write, delayMs = 0) {
|
|
|
1415
1434
|
stopTimers();
|
|
1416
1435
|
if (!rendered)
|
|
1417
1436
|
return;
|
|
1418
|
-
const verb = progressCompleteVerb(update.mode ?? mode);
|
|
1419
1437
|
const elapsed = update.elapsedMs === void 0 ? "" : ` in ${formatDuration(update.elapsedMs)}`;
|
|
1420
|
-
|
|
1438
|
+
if (update.activity !== void 0) {
|
|
1439
|
+
write(`[Progress] ${update.activity}: ${formatCount(update.total, update.unit ?? DEFAULT_COUNT_UNIT, "words")}${elapsed}.
|
|
1440
|
+
`);
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1443
|
+
const verb = progressCompleteVerb(update.mode ?? mode);
|
|
1444
|
+
write(`[Progress] ${verb} project index: ${formatCount(update.total, DEFAULT_COUNT_UNIT, "words")}${elapsed}.
|
|
1421
1445
|
`);
|
|
1422
1446
|
return;
|
|
1423
1447
|
}
|
|
@@ -1430,6 +1454,10 @@ function createLogProgressDisplay(write, delayMs = 0) {
|
|
|
1430
1454
|
current = update.current;
|
|
1431
1455
|
total = update.total;
|
|
1432
1456
|
mode = update.mode ?? mode;
|
|
1457
|
+
if (update.activity !== void 0)
|
|
1458
|
+
unit = update.unit ?? DEFAULT_COUNT_UNIT;
|
|
1459
|
+
else if (update.unit !== void 0)
|
|
1460
|
+
unit = update.unit;
|
|
1433
1461
|
if (update.activity !== void 0)
|
|
1434
1462
|
activity = update.activity;
|
|
1435
1463
|
const activityChanged = activity !== previousActivity;
|
|
@@ -1444,10 +1472,10 @@ function createLogProgressDisplay(write, delayMs = 0) {
|
|
|
1444
1472
|
if (shouldPrintCount) {
|
|
1445
1473
|
const elapsed = formatDuration(performance2.now() - phaseStartedAt);
|
|
1446
1474
|
if (update.activity !== void 0) {
|
|
1447
|
-
write(`[Progress] ${activity}:${formatProgressCount(update.current, update.total)}. (${elapsed})
|
|
1475
|
+
write(`[Progress] ${activity}:${formatProgressCount(update.current, update.total, unit)}. (${elapsed})
|
|
1448
1476
|
`);
|
|
1449
1477
|
} else {
|
|
1450
|
-
write(`[Progress] ${
|
|
1478
|
+
write(`[Progress] ${formatCount(update.current, unit)} processed. (${elapsed})
|
|
1451
1479
|
`);
|
|
1452
1480
|
}
|
|
1453
1481
|
}
|
|
@@ -1480,13 +1508,14 @@ function formatDuration(elapsedMs2) {
|
|
|
1480
1508
|
return `${Math.round(durationMs)}ms`;
|
|
1481
1509
|
return `${(durationMs / 1e3).toFixed(1)}s`;
|
|
1482
1510
|
}
|
|
1483
|
-
var REFRESH_INTERVAL_MS, CLEAR_LINE, SPINNER_FRAMES;
|
|
1511
|
+
var REFRESH_INTERVAL_MS, CLEAR_LINE, SPINNER_FRAMES, DEFAULT_COUNT_UNIT;
|
|
1484
1512
|
var init_progress = __esm({
|
|
1485
1513
|
"dist/cli/progress.js"() {
|
|
1486
1514
|
"use strict";
|
|
1487
1515
|
REFRESH_INTERVAL_MS = 100;
|
|
1488
1516
|
CLEAR_LINE = "\r\x1B[2K";
|
|
1489
1517
|
SPINNER_FRAMES = ["-", "\\", "|", "/"];
|
|
1518
|
+
DEFAULT_COUNT_UNIT = "file";
|
|
1490
1519
|
}
|
|
1491
1520
|
});
|
|
1492
1521
|
|
|
@@ -9499,12 +9528,14 @@ var init_dist2 = __esm({
|
|
|
9499
9528
|
// dist/util/concurrency.js
|
|
9500
9529
|
var concurrency_exports = {};
|
|
9501
9530
|
__export(concurrency_exports, {
|
|
9531
|
+
EVENT_LOOP_SLICE_MS: () => EVENT_LOOP_SLICE_MS,
|
|
9502
9532
|
Semaphore: () => Semaphore,
|
|
9503
9533
|
delay: () => delay,
|
|
9504
9534
|
getIOSemaphore: () => getIOSemaphore,
|
|
9505
9535
|
mapLimit: () => mapLimit,
|
|
9506
9536
|
mapLimitSemaphore: () => mapLimitSemaphore,
|
|
9507
|
-
resetIOSemaphore: () => resetIOSemaphore
|
|
9537
|
+
resetIOSemaphore: () => resetIOSemaphore,
|
|
9538
|
+
yieldToEventLoop: () => yieldToEventLoop
|
|
9508
9539
|
});
|
|
9509
9540
|
async function mapLimit(items, limit, fn) {
|
|
9510
9541
|
if (!items.length)
|
|
@@ -9572,7 +9603,12 @@ function delay(ms) {
|
|
|
9572
9603
|
setTimeout(resolve3, ms);
|
|
9573
9604
|
return promise3;
|
|
9574
9605
|
}
|
|
9575
|
-
|
|
9606
|
+
function yieldToEventLoop() {
|
|
9607
|
+
const { promise: promise3, resolve: resolve3 } = Promise.withResolvers();
|
|
9608
|
+
setImmediate(resolve3);
|
|
9609
|
+
return promise3;
|
|
9610
|
+
}
|
|
9611
|
+
var Semaphore, globalIOSemaphore, EVENT_LOOP_SLICE_MS;
|
|
9576
9612
|
var init_concurrency = __esm({
|
|
9577
9613
|
"dist/util/concurrency.js"() {
|
|
9578
9614
|
"use strict";
|
|
@@ -9625,6 +9661,7 @@ var init_concurrency = __esm({
|
|
|
9625
9661
|
}
|
|
9626
9662
|
};
|
|
9627
9663
|
globalIOSemaphore = null;
|
|
9664
|
+
EVENT_LOOP_SLICE_MS = 10;
|
|
9628
9665
|
}
|
|
9629
9666
|
});
|
|
9630
9667
|
|
|
@@ -68918,6 +68955,68 @@ var init_unit_cache = __esm({
|
|
|
68918
68955
|
}
|
|
68919
68956
|
});
|
|
68920
68957
|
|
|
68958
|
+
// dist/duplicates/progress.js
|
|
68959
|
+
import { performance as performance4 } from "node:perf_hooks";
|
|
68960
|
+
function createDuplicateProgress(onProgress, startedAt) {
|
|
68961
|
+
if (!onProgress)
|
|
68962
|
+
return void 0;
|
|
68963
|
+
const origin = startedAt ?? performance4.now();
|
|
68964
|
+
let opened = false;
|
|
68965
|
+
let lastYield = performance4.now();
|
|
68966
|
+
return {
|
|
68967
|
+
stage: (activity, current = 0, total = 0, unit) => {
|
|
68968
|
+
onProgress({
|
|
68969
|
+
type: "progress",
|
|
68970
|
+
phase: opened ? "update" : "start",
|
|
68971
|
+
mode: "check",
|
|
68972
|
+
message: activity,
|
|
68973
|
+
activity,
|
|
68974
|
+
current,
|
|
68975
|
+
total,
|
|
68976
|
+
...unit !== void 0 ? { unit } : {}
|
|
68977
|
+
});
|
|
68978
|
+
opened = true;
|
|
68979
|
+
},
|
|
68980
|
+
complete: (units) => {
|
|
68981
|
+
if (!opened)
|
|
68982
|
+
return;
|
|
68983
|
+
onProgress({
|
|
68984
|
+
type: "progress",
|
|
68985
|
+
phase: "complete",
|
|
68986
|
+
mode: "check",
|
|
68987
|
+
message: DUPLICATE_STAGE_DONE,
|
|
68988
|
+
activity: DUPLICATE_STAGE_DONE,
|
|
68989
|
+
current: units,
|
|
68990
|
+
total: units,
|
|
68991
|
+
unit: "unit",
|
|
68992
|
+
elapsedMs: performance4.now() - origin
|
|
68993
|
+
});
|
|
68994
|
+
},
|
|
68995
|
+
yieldPoint: () => {
|
|
68996
|
+
if (performance4.now() - lastYield < YIELD_INTERVAL_MS)
|
|
68997
|
+
return void 0;
|
|
68998
|
+
return new Promise((resolve3) => {
|
|
68999
|
+
setImmediate(() => {
|
|
69000
|
+
lastYield = performance4.now();
|
|
69001
|
+
resolve3();
|
|
69002
|
+
});
|
|
69003
|
+
});
|
|
69004
|
+
}
|
|
69005
|
+
};
|
|
69006
|
+
}
|
|
69007
|
+
var YIELD_INTERVAL_MS, DUPLICATE_STAGE_UNITS, DUPLICATE_STAGE_PAIRS, DUPLICATE_STAGE_SCORING, DUPLICATE_STAGE_GROUPING, DUPLICATE_STAGE_DONE;
|
|
69008
|
+
var init_progress2 = __esm({
|
|
69009
|
+
"dist/duplicates/progress.js"() {
|
|
69010
|
+
"use strict";
|
|
69011
|
+
YIELD_INTERVAL_MS = 50;
|
|
69012
|
+
DUPLICATE_STAGE_UNITS = "Collecting duplicate units";
|
|
69013
|
+
DUPLICATE_STAGE_PAIRS = "Finding candidate pairs";
|
|
69014
|
+
DUPLICATE_STAGE_SCORING = "Scoring candidate pairs";
|
|
69015
|
+
DUPLICATE_STAGE_GROUPING = "Grouping duplicate findings";
|
|
69016
|
+
DUPLICATE_STAGE_DONE = "Detected duplicates";
|
|
69017
|
+
}
|
|
69018
|
+
});
|
|
69019
|
+
|
|
68921
69020
|
// dist/duplicates/units.js
|
|
68922
69021
|
var units_exports = {};
|
|
68923
69022
|
__export(units_exports, {
|
|
@@ -69379,7 +69478,7 @@ function shouldKeepUnit(unit, includeSmall, minTokens) {
|
|
|
69379
69478
|
return true;
|
|
69380
69479
|
return unit.tokenCount >= minTokens;
|
|
69381
69480
|
}
|
|
69382
|
-
async function collectDuplicateUnits(index, options) {
|
|
69481
|
+
async function collectDuplicateUnits(index, options, progress) {
|
|
69383
69482
|
const files = options.files ?? Array.from(index.byFile.values(), (module2) => module2.file);
|
|
69384
69483
|
const filesByIdentity = /* @__PURE__ */ new Map();
|
|
69385
69484
|
for (const file2 of files) {
|
|
@@ -69392,8 +69491,14 @@ async function collectDuplicateUnits(index, options) {
|
|
|
69392
69491
|
const variant = duplicateUnitCacheVariant(index, options.minTokens, options.maxTokens, options.shingleSize, options.windowSize, options.projectRoot);
|
|
69393
69492
|
let belowThresholdUnits = 0;
|
|
69394
69493
|
const belowThresholdUnitsByFile = /* @__PURE__ */ new Map();
|
|
69494
|
+
let sliceStartedAt = performance.now();
|
|
69395
69495
|
const pendingWrites = [];
|
|
69496
|
+
let processedFiles = 0;
|
|
69396
69497
|
for (const file2 of normalizedFiles) {
|
|
69498
|
+
if (performance.now() - sliceStartedAt >= EVENT_LOOP_SLICE_MS) {
|
|
69499
|
+
await yieldToEventLoop();
|
|
69500
|
+
sliceStartedAt = performance.now();
|
|
69501
|
+
}
|
|
69397
69502
|
const fileKey = fileIdentityKey(file2);
|
|
69398
69503
|
const cacheSignature = duplicateUnitCacheSignature(index, file2, options.projectRoot);
|
|
69399
69504
|
let source = index.parsed?.get(fileKey)?.source;
|
|
@@ -69421,9 +69526,18 @@ async function collectDuplicateUnits(index, options) {
|
|
|
69421
69526
|
}
|
|
69422
69527
|
units.push(unit);
|
|
69423
69528
|
}
|
|
69529
|
+
if (progress) {
|
|
69530
|
+
processedFiles++;
|
|
69531
|
+
progress.stage(DUPLICATE_STAGE_UNITS, processedFiles, normalizedFiles.length, "file");
|
|
69532
|
+
const pending = progress.yieldPoint();
|
|
69533
|
+
if (pending)
|
|
69534
|
+
await pending;
|
|
69535
|
+
}
|
|
69424
69536
|
}
|
|
69425
|
-
|
|
69426
|
-
|
|
69537
|
+
for (let start = 0; start < pendingWrites.length; start += DUPLICATE_CACHE_WRITE_SLICE_FILES) {
|
|
69538
|
+
const slice = pendingWrites.slice(start, start + DUPLICATE_CACHE_WRITE_SLICE_FILES);
|
|
69539
|
+
writeDuplicateUnitsBatchToCache(index, slice, options.projectRoot);
|
|
69540
|
+
await yieldToEventLoop();
|
|
69427
69541
|
}
|
|
69428
69542
|
units.sort((left, right) => {
|
|
69429
69543
|
const fileCompare = left.absoluteFile.localeCompare(right.absoluteFile);
|
|
@@ -69464,7 +69578,7 @@ async function buildDuplicateUnitsForFile(index, file2, projectRoot, minTokens,
|
|
|
69464
69578
|
const chunkUnits = makeChunkUnits(file2, chunks, projectRoot, shingleSize, windowSize, astContext);
|
|
69465
69579
|
return [...symbolUnits, ...chunkUnits];
|
|
69466
69580
|
}
|
|
69467
|
-
var DEFAULT_MAX_FINGERPRINTS, textLanguageByExtension, symbolUnitKinds, duplicateImportStatementQueries, graphOnlyImportStatementPatterns;
|
|
69581
|
+
var DEFAULT_MAX_FINGERPRINTS, textLanguageByExtension, symbolUnitKinds, duplicateImportStatementQueries, graphOnlyImportStatementPatterns, DUPLICATE_CACHE_WRITE_SLICE_FILES;
|
|
69468
69582
|
var init_units = __esm({
|
|
69469
69583
|
"dist/duplicates/units.js"() {
|
|
69470
69584
|
"use strict";
|
|
@@ -69482,8 +69596,10 @@ var init_units = __esm({
|
|
|
69482
69596
|
init_tree_sitter_native();
|
|
69483
69597
|
init_comments();
|
|
69484
69598
|
init_lines();
|
|
69599
|
+
init_concurrency();
|
|
69485
69600
|
init_paths();
|
|
69486
69601
|
init_unit_cache();
|
|
69602
|
+
init_progress2();
|
|
69487
69603
|
DEFAULT_MAX_FINGERPRINTS = 128;
|
|
69488
69604
|
textLanguageByExtension = {
|
|
69489
69605
|
".json": "json",
|
|
@@ -69555,6 +69671,7 @@ var init_units = __esm({
|
|
|
69555
69671
|
astro: /^[\t ]*import\b(?![\t ]*\()(?:[\t ]*["'][^"']*["']|[\s\S]*?\bfrom[\t ]*["'][^"']*["']|[\s\S]*?;)/gmu,
|
|
69556
69672
|
mdx: /^[\t ]*import\b(?![\t ]*\()(?:[\t ]*["'][^"']*["']|[\s\S]*?\bfrom[\t ]*["'][^"']*["']|[\s\S]*?;)/gmu
|
|
69557
69673
|
};
|
|
69674
|
+
DUPLICATE_CACHE_WRITE_SLICE_FILES = 25;
|
|
69558
69675
|
}
|
|
69559
69676
|
});
|
|
69560
69677
|
|
|
@@ -69564,27 +69681,16 @@ __export(scoring_exports, {
|
|
|
69564
69681
|
DEFAULT_GROUP_VARIANT_LIMIT: () => DEFAULT_GROUP_VARIANT_LIMIT,
|
|
69565
69682
|
DEFAULT_LIMIT: () => DEFAULT_LIMIT,
|
|
69566
69683
|
DEFAULT_MAX_BUCKET_SIZE: () => DEFAULT_MAX_BUCKET_SIZE,
|
|
69684
|
+
DEFAULT_MAX_CANDIDATE_PAIRS: () => DEFAULT_MAX_CANDIDATE_PAIRS,
|
|
69567
69685
|
DEFAULT_MAX_TOKENS: () => DEFAULT_MAX_TOKENS,
|
|
69568
69686
|
DEFAULT_MIN_TOKENS: () => DEFAULT_MIN_TOKENS,
|
|
69569
69687
|
DEFAULT_SHINGLE_SIZE: () => DEFAULT_SHINGLE_SIZE,
|
|
69570
69688
|
DEFAULT_WINDOW_SIZE: () => DEFAULT_WINDOW_SIZE,
|
|
69571
69689
|
GROUP_PRIMARY_LENGTH_RATIO_FLOOR: () => GROUP_PRIMARY_LENGTH_RATIO_FLOOR,
|
|
69572
|
-
|
|
69690
|
+
MAX_CANDIDATE_PAIRS_LIMIT: () => MAX_CANDIDATE_PAIRS_LIMIT,
|
|
69573
69691
|
NEARBY_CHUNK_VARIANT_MAX_GAP: () => NEARBY_CHUNK_VARIANT_MAX_GAP,
|
|
69574
|
-
addAlignedSimilarityHintPairs: () => addAlignedSimilarityHintPairs,
|
|
69575
|
-
addBucketPairs: () => addBucketPairs,
|
|
69576
|
-
addBucketsToPairs: () => addBucketsToPairs,
|
|
69577
|
-
addConsideredSignature: () => addConsideredSignature,
|
|
69578
|
-
addPairEvidence: () => addPairEvidence,
|
|
69579
|
-
addSignatureBucketsToPairs: () => addSignatureBucketsToPairs,
|
|
69580
|
-
addSimilarityHintPair: () => addSimilarityHintPair,
|
|
69581
|
-
addSimilarityHintPairs: () => addSimilarityHintPairs,
|
|
69582
|
-
addToBucket: () => addToBucket,
|
|
69583
69692
|
bestCloneType: () => bestCloneType,
|
|
69584
69693
|
bestConfidence: () => bestConfidence,
|
|
69585
|
-
bucketPairCountExceeds: () => bucketPairCountExceeds,
|
|
69586
|
-
buildCandidatePairs: () => buildCandidatePairs,
|
|
69587
|
-
buildCandidatePairsFromPreparedBuckets: () => buildCandidatePairsFromPreparedBuckets,
|
|
69588
69694
|
cleanupLabelsForGroup: () => cleanupLabelsForGroup,
|
|
69589
69695
|
cloneTypeForPair: () => cloneTypeForPair,
|
|
69590
69696
|
cloneTypeRank: () => cloneTypeRank,
|
|
@@ -69603,20 +69709,15 @@ __export(scoring_exports, {
|
|
|
69603
69709
|
duplicateUnitRefQuality: () => duplicateUnitRefQuality,
|
|
69604
69710
|
enrichDuplicateGroups: () => enrichDuplicateGroups,
|
|
69605
69711
|
estimatedLinesSavedForLocations: () => estimatedLinesSavedForLocations,
|
|
69606
|
-
filterPreparedDuplicateBucketMap: () => filterPreparedDuplicateBucketMap,
|
|
69607
|
-
filterPreparedDuplicateBuckets: () => filterPreparedDuplicateBuckets,
|
|
69608
|
-
forEachBucketPair: () => forEachBucketPair,
|
|
69609
69712
|
groupClusterSummary: () => groupClusterSummary,
|
|
69610
69713
|
groupForSuggestions: () => groupForSuggestions,
|
|
69611
69714
|
groupLocations: () => groupLocations,
|
|
69612
69715
|
groupLooksLikeBarrelNoise: () => groupLooksLikeBarrelNoise,
|
|
69613
69716
|
groupLooksLikeImportListNoise: () => groupLooksLikeImportListNoise,
|
|
69614
69717
|
groupSuggestions: () => groupSuggestions,
|
|
69615
|
-
hasEnoughSharedFingerprints: () => hasEnoughSharedFingerprints,
|
|
69616
|
-
hasEnoughSharedFingerprintsFor: () => hasEnoughSharedFingerprintsFor,
|
|
69617
|
-
hasLineOverlap: () => hasLineOverlap,
|
|
69618
69718
|
isFixtureLikeFile: () => isFixtureLikeFile,
|
|
69619
69719
|
isLocationClique: () => isLocationClique,
|
|
69720
|
+
isScorablePair: () => isScorablePair,
|
|
69620
69721
|
isTestFile: () => isTestFile,
|
|
69621
69722
|
lineOverlap: () => lineOverlap,
|
|
69622
69723
|
locationsForSuggestions: () => locationsForSuggestions,
|
|
@@ -69627,21 +69728,16 @@ __export(scoring_exports, {
|
|
|
69627
69728
|
metricsForPair: () => metricsForPair,
|
|
69628
69729
|
normalizeConfidence: () => normalizeConfidence,
|
|
69629
69730
|
normalizeIntegerOption: () => normalizeIntegerOption,
|
|
69731
|
+
normalizeMaxCandidatePairsOption: () => normalizeMaxCandidatePairsOption,
|
|
69630
69732
|
normalizeNonNegativeIntegerOption: () => normalizeNonNegativeIntegerOption,
|
|
69631
69733
|
normalizePositiveIntegerOption: () => normalizePositiveIntegerOption,
|
|
69632
|
-
normalizeSimilarityHintFile: () => normalizeSimilarityHintFile,
|
|
69633
69734
|
orderedGroupKey: () => orderedGroupKey,
|
|
69634
|
-
orderedPair: () => orderedPair,
|
|
69635
69735
|
orderedUnitPairKey: () => orderedUnitPairKey,
|
|
69636
69736
|
orderedUnitRangePairKey: () => orderedUnitRangePairKey,
|
|
69637
|
-
pairKey: () => pairKey,
|
|
69638
69737
|
preferredDuplicateUnitRef: () => preferredDuplicateUnitRef,
|
|
69639
|
-
prepareDuplicateCandidateBuckets: () => prepareDuplicateCandidateBuckets,
|
|
69640
69738
|
reducedLinesForPair: () => reducedLinesForPair,
|
|
69641
69739
|
scorePair: () => scorePair,
|
|
69642
69740
|
shouldScoreSignatureEvidence: () => shouldScoreSignatureEvidence,
|
|
69643
|
-
similarityAlignmentKey: () => similarityAlignmentKey,
|
|
69644
|
-
similarityHintPairCountExceeds: () => similarityHintPairCountExceeds,
|
|
69645
69741
|
singletonUnitCluster: () => singletonUnitCluster,
|
|
69646
69742
|
suggestionForPair: () => suggestionForPair,
|
|
69647
69743
|
suggestionPrimaryRank: () => suggestionPrimaryRank,
|
|
@@ -69686,14 +69782,6 @@ function ratio(left, right) {
|
|
|
69686
69782
|
return 0;
|
|
69687
69783
|
return Math.min(left, right) / Math.max(left, right);
|
|
69688
69784
|
}
|
|
69689
|
-
function normalizeSimilarityIndex(value) {
|
|
69690
|
-
if (!Number.isFinite(value))
|
|
69691
|
-
return void 0;
|
|
69692
|
-
const bounded = Math.max(0, Math.min(100, Math.round(value)));
|
|
69693
|
-
if (bounded < MIN_SIMILARITY_HINT_INDEX)
|
|
69694
|
-
return void 0;
|
|
69695
|
-
return bounded;
|
|
69696
|
-
}
|
|
69697
69785
|
function jaccard(left, right) {
|
|
69698
69786
|
if (!left.size && !right.size)
|
|
69699
69787
|
return 1;
|
|
@@ -69723,6 +69811,13 @@ function normalizePositiveIntegerOption(value, optionName2, fallback) {
|
|
|
69723
69811
|
function normalizeNonNegativeIntegerOption(value, optionName2, fallback) {
|
|
69724
69812
|
return normalizeIntegerOption(value, optionName2, fallback, 0, "a non-negative integer");
|
|
69725
69813
|
}
|
|
69814
|
+
function normalizeMaxCandidatePairsOption(value) {
|
|
69815
|
+
const resolved = normalizePositiveIntegerOption(value, "maxCandidatePairs", DEFAULT_MAX_CANDIDATE_PAIRS);
|
|
69816
|
+
if (resolved > MAX_CANDIDATE_PAIRS_LIMIT) {
|
|
69817
|
+
throw new Error(`Invalid maxCandidatePairs value "${resolved}". Expected an integer from 1 to ${MAX_CANDIDATE_PAIRS_LIMIT}.`);
|
|
69818
|
+
}
|
|
69819
|
+
return resolved;
|
|
69820
|
+
}
|
|
69726
69821
|
function bestConfidence(left, right) {
|
|
69727
69822
|
if (confidenceRank[left] >= confidenceRank[right])
|
|
69728
69823
|
return left;
|
|
@@ -69759,182 +69854,15 @@ function shouldScoreSignatureEvidence(evidence, metrics) {
|
|
|
69759
69854
|
}
|
|
69760
69855
|
return metrics.shingleOverlap >= 0.55;
|
|
69761
69856
|
}
|
|
69762
|
-
function pairKey(left, right) {
|
|
69763
|
-
if (left.id < right.id)
|
|
69764
|
-
return `${left.id}\0${right.id}`;
|
|
69765
|
-
return `${right.id}\0${left.id}`;
|
|
69766
|
-
}
|
|
69767
|
-
function orderedPair(left, right) {
|
|
69768
|
-
if (left.absoluteFile < right.absoluteFile)
|
|
69769
|
-
return [left, right];
|
|
69770
|
-
if (left.absoluteFile > right.absoluteFile)
|
|
69771
|
-
return [right, left];
|
|
69772
|
-
if (left.startLine <= right.startLine)
|
|
69773
|
-
return [left, right];
|
|
69774
|
-
return [right, left];
|
|
69775
|
-
}
|
|
69776
69857
|
function hasLineOverlap(left, right) {
|
|
69777
69858
|
if (left.absoluteFile !== right.absoluteFile)
|
|
69778
69859
|
return false;
|
|
69779
69860
|
return left.startLine <= right.endLine && right.startLine <= left.endLine;
|
|
69780
69861
|
}
|
|
69781
|
-
function
|
|
69782
|
-
|
|
69783
|
-
const existing = pairs.get(key);
|
|
69784
|
-
if (existing) {
|
|
69785
|
-
if (evidenceKind === "signature") {
|
|
69786
|
-
existing.signatureMatches++;
|
|
69787
|
-
} else {
|
|
69788
|
-
existing[evidenceKind] = true;
|
|
69789
|
-
}
|
|
69790
|
-
return;
|
|
69791
|
-
}
|
|
69792
|
-
pairs.set(key, {
|
|
69793
|
-
left,
|
|
69794
|
-
right,
|
|
69795
|
-
rawHash: evidenceKind === "rawHash",
|
|
69796
|
-
normalizedHash: evidenceKind === "normalizedHash",
|
|
69797
|
-
astShape: evidenceKind === "astShape",
|
|
69798
|
-
signature: false,
|
|
69799
|
-
signatureMatches: evidenceKind === "signature" ? 1 : 0
|
|
69800
|
-
});
|
|
69801
|
-
}
|
|
69802
|
-
function forEachBucketPair(bucket, pairFilter, unitFilter, visit2) {
|
|
69803
|
-
if (unitFilter) {
|
|
69804
|
-
const targetUnits = bucket.filter(unitFilter);
|
|
69805
|
-
const seenPairs = /* @__PURE__ */ new Set();
|
|
69806
|
-
for (const targetUnit of targetUnits) {
|
|
69807
|
-
for (const otherUnit of bucket) {
|
|
69808
|
-
if (targetUnit.id === otherUnit.id)
|
|
69809
|
-
continue;
|
|
69810
|
-
const [left, right] = orderedPair(targetUnit, otherUnit);
|
|
69811
|
-
const key = pairKey(left, right);
|
|
69812
|
-
if (seenPairs.has(key))
|
|
69813
|
-
continue;
|
|
69814
|
-
seenPairs.add(key);
|
|
69815
|
-
if (pairFilter && !pairFilter(left, right))
|
|
69816
|
-
continue;
|
|
69817
|
-
visit2(left, right);
|
|
69818
|
-
}
|
|
69819
|
-
}
|
|
69820
|
-
return;
|
|
69821
|
-
}
|
|
69822
|
-
for (let i = 0; i < bucket.length; i++) {
|
|
69823
|
-
for (let j = i + 1; j < bucket.length; j++) {
|
|
69824
|
-
const [left, right] = orderedPair(bucket[i], bucket[j]);
|
|
69825
|
-
if (pairFilter && !pairFilter(left, right))
|
|
69826
|
-
continue;
|
|
69827
|
-
visit2(left, right);
|
|
69828
|
-
}
|
|
69829
|
-
}
|
|
69830
|
-
}
|
|
69831
|
-
function addBucketPairs(bucket, pairs, evidenceKind, pairFilter, unitFilter) {
|
|
69832
|
-
forEachBucketPair(bucket, pairFilter, unitFilter, (left, right) => {
|
|
69833
|
-
addPairEvidence(pairs, evidenceKind, left, right);
|
|
69834
|
-
});
|
|
69835
|
-
}
|
|
69836
|
-
function bucketPairCountExceeds(bucket, limit, pairFilter, unitFilter) {
|
|
69837
|
-
let count = 0;
|
|
69838
|
-
const leftUnits = unitFilter ? bucket.filter(unitFilter) : bucket;
|
|
69839
|
-
if (!leftUnits.length)
|
|
69862
|
+
function isScorablePair(left, right, crossFileOnly) {
|
|
69863
|
+
if (crossFileOnly && left.absoluteFile === right.absoluteFile)
|
|
69840
69864
|
return false;
|
|
69841
|
-
|
|
69842
|
-
for (const leftUnit of leftUnits) {
|
|
69843
|
-
for (const rightUnit of bucket) {
|
|
69844
|
-
if (leftUnit.id === rightUnit.id)
|
|
69845
|
-
continue;
|
|
69846
|
-
const [left, right] = orderedPair(leftUnit, rightUnit);
|
|
69847
|
-
const key = pairKey(left, right);
|
|
69848
|
-
if (seenPairs.has(key))
|
|
69849
|
-
continue;
|
|
69850
|
-
seenPairs.add(key);
|
|
69851
|
-
if (!pairFilter(left, right))
|
|
69852
|
-
continue;
|
|
69853
|
-
count++;
|
|
69854
|
-
if (count > limit)
|
|
69855
|
-
return true;
|
|
69856
|
-
}
|
|
69857
|
-
}
|
|
69858
|
-
return false;
|
|
69859
|
-
}
|
|
69860
|
-
function addBucketsToPairs(buckets, pairs, evidenceKind, maxBucketSize, pairFilter, unitFilter) {
|
|
69861
|
-
let oversizedBuckets = 0;
|
|
69862
|
-
for (const bucket of buckets.values()) {
|
|
69863
|
-
if (bucket.length < 2)
|
|
69864
|
-
continue;
|
|
69865
|
-
if (unitFilter && !bucket.some(unitFilter))
|
|
69866
|
-
continue;
|
|
69867
|
-
if (bucket.length > maxBucketSize) {
|
|
69868
|
-
if (!pairFilter || bucketPairCountExceeds(bucket, maxBucketSize, pairFilter, unitFilter)) {
|
|
69869
|
-
oversizedBuckets++;
|
|
69870
|
-
continue;
|
|
69871
|
-
}
|
|
69872
|
-
}
|
|
69873
|
-
addBucketPairs(bucket, pairs, evidenceKind, pairFilter, unitFilter);
|
|
69874
|
-
}
|
|
69875
|
-
return oversizedBuckets;
|
|
69876
|
-
}
|
|
69877
|
-
function addConsideredSignature(consideredSignaturesByUnit, unit, signature) {
|
|
69878
|
-
const signatures = consideredSignaturesByUnit.get(unit.id);
|
|
69879
|
-
if (signatures) {
|
|
69880
|
-
signatures.add(signature);
|
|
69881
|
-
return;
|
|
69882
|
-
}
|
|
69883
|
-
consideredSignaturesByUnit.set(unit.id, /* @__PURE__ */ new Set([signature]));
|
|
69884
|
-
}
|
|
69885
|
-
function addSignatureBucketsToPairs(buckets, pairs, consideredSignaturesByUnit, maxBucketSize, pairFilter, unitFilter) {
|
|
69886
|
-
const signatureMatchCounts = /* @__PURE__ */ new Map();
|
|
69887
|
-
const signatureMatchUnits = /* @__PURE__ */ new Map();
|
|
69888
|
-
let oversizedBuckets = 0;
|
|
69889
|
-
for (const [signature, bucket] of buckets) {
|
|
69890
|
-
if (bucket.length < 2)
|
|
69891
|
-
continue;
|
|
69892
|
-
if (unitFilter && !bucket.some(unitFilter))
|
|
69893
|
-
continue;
|
|
69894
|
-
if (bucket.length > maxBucketSize) {
|
|
69895
|
-
if (!pairFilter || bucketPairCountExceeds(bucket, maxBucketSize, pairFilter, unitFilter)) {
|
|
69896
|
-
oversizedBuckets++;
|
|
69897
|
-
continue;
|
|
69898
|
-
}
|
|
69899
|
-
}
|
|
69900
|
-
for (const unit of bucket) {
|
|
69901
|
-
addConsideredSignature(consideredSignaturesByUnit, unit, signature);
|
|
69902
|
-
}
|
|
69903
|
-
forEachBucketPair(bucket, pairFilter, unitFilter, (left, right) => {
|
|
69904
|
-
const key = pairKey(left, right);
|
|
69905
|
-
const next = (signatureMatchCounts.get(key) ?? 0) + 1;
|
|
69906
|
-
signatureMatchCounts.set(key, next);
|
|
69907
|
-
if (next === 2 && !pairs.has(key) && !signatureMatchUnits.has(key)) {
|
|
69908
|
-
signatureMatchUnits.set(key, [left, right]);
|
|
69909
|
-
}
|
|
69910
|
-
});
|
|
69911
|
-
}
|
|
69912
|
-
for (const [key, count] of signatureMatchCounts) {
|
|
69913
|
-
const existing = pairs.get(key);
|
|
69914
|
-
if (existing) {
|
|
69915
|
-
existing.signatureMatches = count;
|
|
69916
|
-
continue;
|
|
69917
|
-
}
|
|
69918
|
-
if (count < 2)
|
|
69919
|
-
continue;
|
|
69920
|
-
const units = signatureMatchUnits.get(key);
|
|
69921
|
-
if (!units)
|
|
69922
|
-
continue;
|
|
69923
|
-
const [left, right] = units;
|
|
69924
|
-
if (!hasEnoughSharedFingerprintsFor(count, left.id, right.id, consideredSignaturesByUnit)) {
|
|
69925
|
-
continue;
|
|
69926
|
-
}
|
|
69927
|
-
pairs.set(key, {
|
|
69928
|
-
left,
|
|
69929
|
-
right,
|
|
69930
|
-
rawHash: false,
|
|
69931
|
-
normalizedHash: false,
|
|
69932
|
-
astShape: false,
|
|
69933
|
-
signature: false,
|
|
69934
|
-
signatureMatches: count
|
|
69935
|
-
});
|
|
69936
|
-
}
|
|
69937
|
-
return oversizedBuckets;
|
|
69865
|
+
return !hasLineOverlap(left, right);
|
|
69938
69866
|
}
|
|
69939
69867
|
function scorePair(evidence, metrics) {
|
|
69940
69868
|
let score = 0;
|
|
@@ -69993,222 +69921,6 @@ function metricsForPair(evidence) {
|
|
|
69993
69921
|
}
|
|
69994
69922
|
return metrics;
|
|
69995
69923
|
}
|
|
69996
|
-
function addToBucket(buckets, key, unit) {
|
|
69997
|
-
appendToArrayMap(buckets, key, unit);
|
|
69998
|
-
}
|
|
69999
|
-
function prepareDuplicateCandidateBuckets(units) {
|
|
70000
|
-
const rawHashBuckets = /* @__PURE__ */ new Map();
|
|
70001
|
-
const normalizedHashBuckets = /* @__PURE__ */ new Map();
|
|
70002
|
-
const astShapeBuckets = /* @__PURE__ */ new Map();
|
|
70003
|
-
const signatureBuckets = /* @__PURE__ */ new Map();
|
|
70004
|
-
for (const unit of units) {
|
|
70005
|
-
const languagePrefix = `${unit.languageId}:`;
|
|
70006
|
-
addToBucket(rawHashBuckets, `${languagePrefix}${unit.rawHash}`, unit);
|
|
70007
|
-
addToBucket(normalizedHashBuckets, `${languagePrefix}${unit.normalizedHash}`, unit);
|
|
70008
|
-
if (unit.astShapeHash !== void 0) {
|
|
70009
|
-
addToBucket(astShapeBuckets, `${languagePrefix}${unit.astShapeHash}`, unit);
|
|
70010
|
-
}
|
|
70011
|
-
for (const signature of unit.signatures) {
|
|
70012
|
-
addToBucket(signatureBuckets, `${languagePrefix}${signature}`, unit);
|
|
70013
|
-
}
|
|
70014
|
-
}
|
|
70015
|
-
return {
|
|
70016
|
-
units,
|
|
70017
|
-
rawHashBuckets,
|
|
70018
|
-
normalizedHashBuckets,
|
|
70019
|
-
astShapeBuckets,
|
|
70020
|
-
signatureBuckets
|
|
70021
|
-
};
|
|
70022
|
-
}
|
|
70023
|
-
function filterPreparedDuplicateBucketMap(buckets, unitFilter) {
|
|
70024
|
-
const filteredBuckets = /* @__PURE__ */ new Map();
|
|
70025
|
-
for (const [key, bucket] of buckets) {
|
|
70026
|
-
const filteredBucket = bucket.filter(unitFilter);
|
|
70027
|
-
if (filteredBucket.length)
|
|
70028
|
-
filteredBuckets.set(key, filteredBucket);
|
|
70029
|
-
}
|
|
70030
|
-
return filteredBuckets;
|
|
70031
|
-
}
|
|
70032
|
-
function filterPreparedDuplicateBuckets(preparedBuckets, unitFilter) {
|
|
70033
|
-
return {
|
|
70034
|
-
units: preparedBuckets.units.filter(unitFilter),
|
|
70035
|
-
rawHashBuckets: filterPreparedDuplicateBucketMap(preparedBuckets.rawHashBuckets, unitFilter),
|
|
70036
|
-
normalizedHashBuckets: filterPreparedDuplicateBucketMap(preparedBuckets.normalizedHashBuckets, unitFilter),
|
|
70037
|
-
astShapeBuckets: filterPreparedDuplicateBucketMap(preparedBuckets.astShapeBuckets, unitFilter),
|
|
70038
|
-
signatureBuckets: filterPreparedDuplicateBucketMap(preparedBuckets.signatureBuckets, unitFilter)
|
|
70039
|
-
};
|
|
70040
|
-
}
|
|
70041
|
-
function buildCandidatePairsFromPreparedBuckets(preparedBuckets, maxBucketSize, similarityHints, projectRoot, pairFilter, unitFilter) {
|
|
70042
|
-
const pairs = /* @__PURE__ */ new Map();
|
|
70043
|
-
const consideredSignaturesByUnit = /* @__PURE__ */ new Map();
|
|
70044
|
-
let oversizedBuckets = 0;
|
|
70045
|
-
oversizedBuckets += addBucketsToPairs(preparedBuckets.rawHashBuckets, pairs, "rawHash", maxBucketSize, pairFilter, unitFilter);
|
|
70046
|
-
oversizedBuckets += addBucketsToPairs(preparedBuckets.normalizedHashBuckets, pairs, "normalizedHash", maxBucketSize, pairFilter, unitFilter);
|
|
70047
|
-
oversizedBuckets += addBucketsToPairs(preparedBuckets.astShapeBuckets, pairs, "astShape", maxBucketSize, pairFilter, unitFilter);
|
|
70048
|
-
oversizedBuckets += addSimilarityHintPairs(preparedBuckets.units, pairs, similarityHints, projectRoot, maxBucketSize, pairFilter);
|
|
70049
|
-
oversizedBuckets += addSignatureBucketsToPairs(preparedBuckets.signatureBuckets, pairs, consideredSignaturesByUnit, maxBucketSize, pairFilter, unitFilter);
|
|
70050
|
-
for (const [key, evidence] of pairs) {
|
|
70051
|
-
if (hasEnoughSharedFingerprints(evidence, consideredSignaturesByUnit)) {
|
|
70052
|
-
evidence.signature = true;
|
|
70053
|
-
continue;
|
|
70054
|
-
}
|
|
70055
|
-
if (!evidence.rawHash && !evidence.normalizedHash && !evidence.astShape && evidence.gitSimilarity === void 0) {
|
|
70056
|
-
pairs.delete(key);
|
|
70057
|
-
}
|
|
70058
|
-
}
|
|
70059
|
-
return { pairs, oversizedBuckets };
|
|
70060
|
-
}
|
|
70061
|
-
function buildCandidatePairs(units, maxBucketSize, similarityHints, projectRoot, pairFilter, unitFilter) {
|
|
70062
|
-
return buildCandidatePairsFromPreparedBuckets(prepareDuplicateCandidateBuckets(units), maxBucketSize, similarityHints, projectRoot, pairFilter, unitFilter);
|
|
70063
|
-
}
|
|
70064
|
-
function addSimilarityHintPairs(units, pairs, similarityHints, projectRoot, maxBucketSize, pairFilter) {
|
|
70065
|
-
if (!similarityHints?.length)
|
|
70066
|
-
return 0;
|
|
70067
|
-
const unitsByFile = /* @__PURE__ */ new Map();
|
|
70068
|
-
for (const unit of units) {
|
|
70069
|
-
const bucket = unitsByFile.get(unit.absoluteFile);
|
|
70070
|
-
if (bucket) {
|
|
70071
|
-
bucket.push(unit);
|
|
70072
|
-
} else {
|
|
70073
|
-
unitsByFile.set(unit.absoluteFile, [unit]);
|
|
70074
|
-
}
|
|
70075
|
-
}
|
|
70076
|
-
let oversizedHints = 0;
|
|
70077
|
-
for (const hint of similarityHints) {
|
|
70078
|
-
const similarityIndex = normalizeSimilarityIndex(hint.similarityIndex);
|
|
70079
|
-
if (similarityIndex === void 0)
|
|
70080
|
-
continue;
|
|
70081
|
-
const leftFile = normalizeSimilarityHintFile(hint.leftFile, projectRoot);
|
|
70082
|
-
const rightFile = normalizeSimilarityHintFile(hint.rightFile, projectRoot);
|
|
70083
|
-
if (!leftFile || !rightFile || leftFile === rightFile)
|
|
70084
|
-
continue;
|
|
70085
|
-
const leftUnits = unitsByFile.get(leftFile);
|
|
70086
|
-
const rightUnits = unitsByFile.get(rightFile);
|
|
70087
|
-
if (!leftUnits?.length || !rightUnits?.length)
|
|
70088
|
-
continue;
|
|
70089
|
-
if (similarityHintPairCountExceeds(leftUnits, rightUnits, maxBucketSize, pairFilter)) {
|
|
70090
|
-
oversizedHints++;
|
|
70091
|
-
addAlignedSimilarityHintPairs(pairs, leftUnits, rightUnits, similarityIndex, maxBucketSize, pairFilter);
|
|
70092
|
-
continue;
|
|
70093
|
-
}
|
|
70094
|
-
for (const leftUnit of leftUnits) {
|
|
70095
|
-
for (const rightUnit of rightUnits) {
|
|
70096
|
-
if (leftUnit.languageId !== rightUnit.languageId)
|
|
70097
|
-
continue;
|
|
70098
|
-
const [left, right] = orderedPair(leftUnit, rightUnit);
|
|
70099
|
-
if (pairFilter && !pairFilter(left, right))
|
|
70100
|
-
continue;
|
|
70101
|
-
addSimilarityHintPair(pairs, left, right, similarityIndex);
|
|
70102
|
-
}
|
|
70103
|
-
}
|
|
70104
|
-
}
|
|
70105
|
-
return oversizedHints;
|
|
70106
|
-
}
|
|
70107
|
-
function similarityHintPairCountExceeds(leftUnits, rightUnits, limit, pairFilter) {
|
|
70108
|
-
let count = 0;
|
|
70109
|
-
for (const leftUnit of leftUnits) {
|
|
70110
|
-
for (const rightUnit of rightUnits) {
|
|
70111
|
-
if (leftUnit.languageId !== rightUnit.languageId)
|
|
70112
|
-
continue;
|
|
70113
|
-
const [left, right] = orderedPair(leftUnit, rightUnit);
|
|
70114
|
-
if (pairFilter && !pairFilter(left, right))
|
|
70115
|
-
continue;
|
|
70116
|
-
count++;
|
|
70117
|
-
if (count > limit)
|
|
70118
|
-
return true;
|
|
70119
|
-
}
|
|
70120
|
-
}
|
|
70121
|
-
return false;
|
|
70122
|
-
}
|
|
70123
|
-
function similarityAlignmentKey(unit) {
|
|
70124
|
-
return [unit.languageId, unit.kind, unit.symbolKind ?? ""].join(":");
|
|
70125
|
-
}
|
|
70126
|
-
function addAlignedSimilarityHintPairs(pairs, leftUnits, rightUnits, similarityIndex, maxPairs, pairFilter) {
|
|
70127
|
-
const rightByKey = /* @__PURE__ */ new Map();
|
|
70128
|
-
for (const unit of rightUnits) {
|
|
70129
|
-
const key = similarityAlignmentKey(unit);
|
|
70130
|
-
const bucket = rightByKey.get(key);
|
|
70131
|
-
if (bucket)
|
|
70132
|
-
bucket.push(unit);
|
|
70133
|
-
else
|
|
70134
|
-
rightByKey.set(key, [unit]);
|
|
70135
|
-
}
|
|
70136
|
-
for (const bucket of rightByKey.values()) {
|
|
70137
|
-
bucket.sort(compareUnitRefs);
|
|
70138
|
-
}
|
|
70139
|
-
const leftByKey = /* @__PURE__ */ new Map();
|
|
70140
|
-
for (const unit of leftUnits) {
|
|
70141
|
-
const key = similarityAlignmentKey(unit);
|
|
70142
|
-
const bucket = leftByKey.get(key);
|
|
70143
|
-
if (bucket)
|
|
70144
|
-
bucket.push(unit);
|
|
70145
|
-
else
|
|
70146
|
-
leftByKey.set(key, [unit]);
|
|
70147
|
-
}
|
|
70148
|
-
for (const bucket of leftByKey.values()) {
|
|
70149
|
-
bucket.sort(compareUnitRefs);
|
|
70150
|
-
}
|
|
70151
|
-
const seenPairs = /* @__PURE__ */ new Set();
|
|
70152
|
-
let addedPairs = 0;
|
|
70153
|
-
for (const [key, sortedLeftUnits] of Array.from(leftByKey.entries()).sort(([left], [right]) => left.localeCompare(right))) {
|
|
70154
|
-
const sortedRightUnits = rightByKey.get(key);
|
|
70155
|
-
if (!sortedRightUnits?.length)
|
|
70156
|
-
continue;
|
|
70157
|
-
const limit = Math.min(sortedLeftUnits.length, sortedRightUnits.length);
|
|
70158
|
-
for (let index = 0; index < limit; index++) {
|
|
70159
|
-
if (addedPairs >= maxPairs)
|
|
70160
|
-
return;
|
|
70161
|
-
const [left, right] = orderedPair(sortedLeftUnits[index], sortedRightUnits[index]);
|
|
70162
|
-
const pairId = pairKey(left, right);
|
|
70163
|
-
if (seenPairs.has(pairId))
|
|
70164
|
-
continue;
|
|
70165
|
-
seenPairs.add(pairId);
|
|
70166
|
-
if (pairFilter && !pairFilter(left, right))
|
|
70167
|
-
continue;
|
|
70168
|
-
addSimilarityHintPair(pairs, left, right, similarityIndex);
|
|
70169
|
-
addedPairs++;
|
|
70170
|
-
}
|
|
70171
|
-
}
|
|
70172
|
-
}
|
|
70173
|
-
function normalizeSimilarityHintFile(file2, projectRoot) {
|
|
70174
|
-
try {
|
|
70175
|
-
return normalizeDetectionFile(file2, projectRoot);
|
|
70176
|
-
} catch {
|
|
70177
|
-
return void 0;
|
|
70178
|
-
}
|
|
70179
|
-
}
|
|
70180
|
-
function addSimilarityHintPair(pairs, left, right, similarityIndex) {
|
|
70181
|
-
const key = pairKey(left, right);
|
|
70182
|
-
const existing = pairs.get(key);
|
|
70183
|
-
if (existing) {
|
|
70184
|
-
existing.gitSimilarity = Math.max(existing.gitSimilarity ?? 0, similarityIndex);
|
|
70185
|
-
return;
|
|
70186
|
-
}
|
|
70187
|
-
pairs.set(key, {
|
|
70188
|
-
left,
|
|
70189
|
-
right,
|
|
70190
|
-
rawHash: false,
|
|
70191
|
-
normalizedHash: false,
|
|
70192
|
-
astShape: false,
|
|
70193
|
-
gitSimilarity: similarityIndex,
|
|
70194
|
-
signature: false,
|
|
70195
|
-
signatureMatches: 0
|
|
70196
|
-
});
|
|
70197
|
-
}
|
|
70198
|
-
function hasEnoughSharedFingerprintsFor(signatureMatches, leftUnitId, rightUnitId, consideredSignaturesByUnit) {
|
|
70199
|
-
if (!signatureMatches)
|
|
70200
|
-
return false;
|
|
70201
|
-
const leftConsideredSignatures = consideredSignaturesByUnit.get(leftUnitId)?.size ?? 0;
|
|
70202
|
-
const rightConsideredSignatures = consideredSignaturesByUnit.get(rightUnitId)?.size ?? 0;
|
|
70203
|
-
const smallerConsideredSignatureCount = Math.min(leftConsideredSignatures, rightConsideredSignatures);
|
|
70204
|
-
if (!smallerConsideredSignatureCount)
|
|
70205
|
-
return false;
|
|
70206
|
-
const minimumShared = Math.max(2, Math.ceil(smallerConsideredSignatureCount * 0.25));
|
|
70207
|
-
return signatureMatches >= minimumShared;
|
|
70208
|
-
}
|
|
70209
|
-
function hasEnoughSharedFingerprints(evidence, consideredSignaturesByUnit) {
|
|
70210
|
-
return hasEnoughSharedFingerprintsFor(evidence.signatureMatches, evidence.left.id, evidence.right.id, consideredSignaturesByUnit);
|
|
70211
|
-
}
|
|
70212
69924
|
function suggestionForPair(evidence) {
|
|
70213
69925
|
const metrics = metricsForPair(evidence);
|
|
70214
69926
|
const { score, reasons } = scorePair(evidence, metrics);
|
|
@@ -70661,13 +70373,22 @@ function enrichDuplicateGroups(groups) {
|
|
|
70661
70373
|
continue;
|
|
70662
70374
|
appendToArrayMap(groupIdsByComponentId, componentId, group.id);
|
|
70663
70375
|
}
|
|
70376
|
+
const clusterByComponentId = /* @__PURE__ */ new Map();
|
|
70664
70377
|
return groups.map((group) => {
|
|
70665
70378
|
const localLocations = locationsByGroupId.get(group.id) ?? groupLocations(group);
|
|
70666
70379
|
const primaryKey = unitRefRangeIdentity(group.primaryLeft);
|
|
70667
70380
|
const componentLocations = componentByKey.get(primaryKey) ?? localLocations;
|
|
70668
70381
|
const componentId = componentIdByKey.get(primaryKey);
|
|
70669
|
-
|
|
70670
|
-
|
|
70382
|
+
let cluster;
|
|
70383
|
+
if (!componentId) {
|
|
70384
|
+
cluster = groupClusterSummary(componentLocations, [group.id], coveredPairs);
|
|
70385
|
+
} else if (clusterByComponentId.has(componentId)) {
|
|
70386
|
+
cluster = clusterByComponentId.get(componentId);
|
|
70387
|
+
} else {
|
|
70388
|
+
const groupIds = Array.from(new Set(groupIdsByComponentId.get(componentId) ?? [group.id])).sort();
|
|
70389
|
+
cluster = groupClusterSummary(componentLocations, groupIds, coveredPairs);
|
|
70390
|
+
clusterByComponentId.set(componentId, cluster);
|
|
70391
|
+
}
|
|
70671
70392
|
const cleanupLabels = cleanupLabelsForGroup(group, localLocations);
|
|
70672
70393
|
if (!cleanupLabels.includes("test-helper-extraction") && cluster) {
|
|
70673
70394
|
if (cluster.files.length && cluster.files.every(isTestFile) && cluster.locationCount >= 3) {
|
|
@@ -70833,7 +70554,7 @@ function groupSuggestions(suggestions, includeRawPairs) {
|
|
|
70833
70554
|
const groups = Array.from(suggestionsByGroup, ([key, value]) => groupForSuggestions(key, value.suggestions, value.left, value.right, variantLimit));
|
|
70834
70555
|
return enrichDuplicateGroups(coalesceDuplicateGroups(groups, variantLimit));
|
|
70835
70556
|
}
|
|
70836
|
-
var DEFAULT_MIN_TOKENS, DEFAULT_MAX_TOKENS, DEFAULT_LIMIT, DEFAULT_MAX_BUCKET_SIZE, DEFAULT_GROUP_VARIANT_LIMIT, DEFAULT_SHINGLE_SIZE, DEFAULT_WINDOW_SIZE, GROUP_PRIMARY_LENGTH_RATIO_FLOOR, NEARBY_CHUNK_VARIANT_MAX_GAP,
|
|
70557
|
+
var DEFAULT_MIN_TOKENS, DEFAULT_MAX_TOKENS, DEFAULT_LIMIT, DEFAULT_MAX_BUCKET_SIZE, DEFAULT_MAX_CANDIDATE_PAIRS, MAX_CANDIDATE_PAIRS_LIMIT, DEFAULT_GROUP_VARIANT_LIMIT, DEFAULT_SHINGLE_SIZE, DEFAULT_WINDOW_SIZE, GROUP_PRIMARY_LENGTH_RATIO_FLOOR, NEARBY_CHUNK_VARIANT_MAX_GAP, confidenceRank, cloneTypeRank;
|
|
70837
70558
|
var init_scoring = __esm({
|
|
70838
70559
|
"dist/duplicates/scoring.js"() {
|
|
70839
70560
|
"use strict";
|
|
@@ -70843,12 +70564,13 @@ var init_scoring = __esm({
|
|
|
70843
70564
|
DEFAULT_MAX_TOKENS = 800;
|
|
70844
70565
|
DEFAULT_LIMIT = 50;
|
|
70845
70566
|
DEFAULT_MAX_BUCKET_SIZE = 200;
|
|
70567
|
+
DEFAULT_MAX_CANDIDATE_PAIRS = 2e6;
|
|
70568
|
+
MAX_CANDIDATE_PAIRS_LIMIT = 16e6;
|
|
70846
70569
|
DEFAULT_GROUP_VARIANT_LIMIT = 5;
|
|
70847
70570
|
DEFAULT_SHINGLE_SIZE = 5;
|
|
70848
70571
|
DEFAULT_WINDOW_SIZE = 4;
|
|
70849
70572
|
GROUP_PRIMARY_LENGTH_RATIO_FLOOR = 0.7;
|
|
70850
70573
|
NEARBY_CHUNK_VARIANT_MAX_GAP = 2;
|
|
70851
|
-
MIN_SIMILARITY_HINT_INDEX = 80;
|
|
70852
70574
|
confidenceRank = {
|
|
70853
70575
|
low: 1,
|
|
70854
70576
|
medium: 2,
|
|
@@ -70863,6 +70585,827 @@ var init_scoring = __esm({
|
|
|
70863
70585
|
}
|
|
70864
70586
|
});
|
|
70865
70587
|
|
|
70588
|
+
// dist/duplicates/candidates.js
|
|
70589
|
+
var candidates_exports = {};
|
|
70590
|
+
__export(candidates_exports, {
|
|
70591
|
+
buildCandidatePairs: () => buildCandidatePairs,
|
|
70592
|
+
filterPreparedDuplicateBuckets: () => filterPreparedDuplicateBuckets,
|
|
70593
|
+
orderedPair: () => orderedPair,
|
|
70594
|
+
prepareDuplicateCandidateBuckets: () => prepareDuplicateCandidateBuckets
|
|
70595
|
+
});
|
|
70596
|
+
function prepareDuplicateCandidateBuckets(units) {
|
|
70597
|
+
const rawHashBuckets = /* @__PURE__ */ new Map();
|
|
70598
|
+
const normalizedHashBuckets = /* @__PURE__ */ new Map();
|
|
70599
|
+
const astShapeBuckets = /* @__PURE__ */ new Map();
|
|
70600
|
+
const signatureBuckets = /* @__PURE__ */ new Map();
|
|
70601
|
+
for (const unit of units) {
|
|
70602
|
+
const languagePrefix = `${unit.languageId}:`;
|
|
70603
|
+
appendToArrayMap(rawHashBuckets, `${languagePrefix}${unit.rawHash}`, unit);
|
|
70604
|
+
appendToArrayMap(normalizedHashBuckets, `${languagePrefix}${unit.normalizedHash}`, unit);
|
|
70605
|
+
if (unit.astShapeHash !== void 0) {
|
|
70606
|
+
appendToArrayMap(astShapeBuckets, `${languagePrefix}${unit.astShapeHash}`, unit);
|
|
70607
|
+
}
|
|
70608
|
+
for (const signature of unit.signatures) {
|
|
70609
|
+
appendToArrayMap(signatureBuckets, `${languagePrefix}${signature}`, unit);
|
|
70610
|
+
}
|
|
70611
|
+
}
|
|
70612
|
+
return {
|
|
70613
|
+
units,
|
|
70614
|
+
rawHashBuckets,
|
|
70615
|
+
normalizedHashBuckets,
|
|
70616
|
+
astShapeBuckets,
|
|
70617
|
+
signatureBuckets
|
|
70618
|
+
};
|
|
70619
|
+
}
|
|
70620
|
+
function filterPreparedDuplicateBucketMap(buckets, unitFilter) {
|
|
70621
|
+
const filteredBuckets = /* @__PURE__ */ new Map();
|
|
70622
|
+
for (const [key, bucket] of buckets) {
|
|
70623
|
+
const filteredBucket = bucket.filter(unitFilter);
|
|
70624
|
+
if (filteredBucket.length)
|
|
70625
|
+
filteredBuckets.set(key, filteredBucket);
|
|
70626
|
+
}
|
|
70627
|
+
return filteredBuckets;
|
|
70628
|
+
}
|
|
70629
|
+
function filterPreparedDuplicateBuckets(preparedBuckets, unitFilter) {
|
|
70630
|
+
return {
|
|
70631
|
+
units: preparedBuckets.units.filter(unitFilter),
|
|
70632
|
+
rawHashBuckets: filterPreparedDuplicateBucketMap(preparedBuckets.rawHashBuckets, unitFilter),
|
|
70633
|
+
normalizedHashBuckets: filterPreparedDuplicateBucketMap(preparedBuckets.normalizedHashBuckets, unitFilter),
|
|
70634
|
+
astShapeBuckets: filterPreparedDuplicateBucketMap(preparedBuckets.astShapeBuckets, unitFilter),
|
|
70635
|
+
signatureBuckets: filterPreparedDuplicateBucketMap(preparedBuckets.signatureBuckets, unitFilter)
|
|
70636
|
+
};
|
|
70637
|
+
}
|
|
70638
|
+
function createUnitIndex(units) {
|
|
70639
|
+
const positions = /* @__PURE__ */ new Map();
|
|
70640
|
+
const firstById = /* @__PURE__ */ new Map();
|
|
70641
|
+
const canon = new Int32Array(units.length);
|
|
70642
|
+
let hasSharedIds = false;
|
|
70643
|
+
for (let position = 0; position < units.length; position++) {
|
|
70644
|
+
const unit = units[position];
|
|
70645
|
+
positions.set(unit, position);
|
|
70646
|
+
const first = firstById.get(unit.id);
|
|
70647
|
+
if (first === void 0) {
|
|
70648
|
+
firstById.set(unit.id, position);
|
|
70649
|
+
canon[position] = position;
|
|
70650
|
+
} else {
|
|
70651
|
+
canon[position] = first;
|
|
70652
|
+
hasSharedIds = true;
|
|
70653
|
+
}
|
|
70654
|
+
}
|
|
70655
|
+
return { units, positions, canon, hasSharedIds };
|
|
70656
|
+
}
|
|
70657
|
+
function positionOf(index, unit) {
|
|
70658
|
+
const position = index.positions.get(unit);
|
|
70659
|
+
if (position === void 0)
|
|
70660
|
+
throw new Error(`Duplicate unit ${unit.id} is not part of the prepared candidates.`);
|
|
70661
|
+
return position;
|
|
70662
|
+
}
|
|
70663
|
+
function canonOf(index, unit) {
|
|
70664
|
+
return index.canon[positionOf(index, unit)];
|
|
70665
|
+
}
|
|
70666
|
+
function pairNumber(index, left, right) {
|
|
70667
|
+
const radix = index.units.length;
|
|
70668
|
+
return left <= right ? left * radix + right : right * radix + left;
|
|
70669
|
+
}
|
|
70670
|
+
function orderedPair(left, right) {
|
|
70671
|
+
if (left.absoluteFile < right.absoluteFile)
|
|
70672
|
+
return [left, right];
|
|
70673
|
+
if (left.absoluteFile > right.absoluteFile)
|
|
70674
|
+
return [right, left];
|
|
70675
|
+
if (left.startLine <= right.startLine)
|
|
70676
|
+
return [left, right];
|
|
70677
|
+
return [right, left];
|
|
70678
|
+
}
|
|
70679
|
+
function blankEvidence(left, right) {
|
|
70680
|
+
return { left, right, rawHash: false, normalizedHash: false, astShape: false, signature: false, signatureMatches: 0 };
|
|
70681
|
+
}
|
|
70682
|
+
function tallyUnscorable(state, key) {
|
|
70683
|
+
if (state.unscorable.size < state.limit)
|
|
70684
|
+
state.unscorable.add(key);
|
|
70685
|
+
}
|
|
70686
|
+
function takePair(state, key, first, second) {
|
|
70687
|
+
const existing = state.pairs.get(key);
|
|
70688
|
+
if (existing)
|
|
70689
|
+
return existing;
|
|
70690
|
+
if (!isScorablePair(first, second, state.crossFileOnly)) {
|
|
70691
|
+
tallyUnscorable(state, key);
|
|
70692
|
+
return void 0;
|
|
70693
|
+
}
|
|
70694
|
+
if (state.pairs.size >= state.limit) {
|
|
70695
|
+
state.skipped++;
|
|
70696
|
+
return void 0;
|
|
70697
|
+
}
|
|
70698
|
+
const [left, right] = orderedPair(first, second);
|
|
70699
|
+
const evidence = blankEvidence(left, right);
|
|
70700
|
+
state.pairs.set(key, evidence);
|
|
70701
|
+
return evidence;
|
|
70702
|
+
}
|
|
70703
|
+
function addStrongEvidence(state, kind, first, second, key) {
|
|
70704
|
+
const evidence = takePair(state, key, first, second);
|
|
70705
|
+
if (evidence)
|
|
70706
|
+
evidence[kind] = true;
|
|
70707
|
+
}
|
|
70708
|
+
function forEachFilteredBucketPair(index, bucket, filter, visit2) {
|
|
70709
|
+
const targetUnits = bucket.filter(filter.unit);
|
|
70710
|
+
const seenPairs = /* @__PURE__ */ new Set();
|
|
70711
|
+
for (const targetUnit of targetUnits) {
|
|
70712
|
+
const targetCanon = canonOf(index, targetUnit);
|
|
70713
|
+
for (const otherUnit of bucket) {
|
|
70714
|
+
if (targetUnit.id === otherUnit.id)
|
|
70715
|
+
continue;
|
|
70716
|
+
const [left, right] = orderedPair(targetUnit, otherUnit);
|
|
70717
|
+
const key = pairNumber(index, targetCanon, canonOf(index, otherUnit));
|
|
70718
|
+
if (seenPairs.has(key))
|
|
70719
|
+
continue;
|
|
70720
|
+
seenPairs.add(key);
|
|
70721
|
+
if (!filter.pair(left, right))
|
|
70722
|
+
continue;
|
|
70723
|
+
visit2(left, right, key);
|
|
70724
|
+
}
|
|
70725
|
+
}
|
|
70726
|
+
}
|
|
70727
|
+
function filteredPairCountExceeds(index, bucket, limit, filter) {
|
|
70728
|
+
let count = 0;
|
|
70729
|
+
const targetUnits = bucket.filter(filter.unit);
|
|
70730
|
+
if (!targetUnits.length)
|
|
70731
|
+
return false;
|
|
70732
|
+
const seenPairs = /* @__PURE__ */ new Set();
|
|
70733
|
+
for (const targetUnit of targetUnits) {
|
|
70734
|
+
const targetCanon = canonOf(index, targetUnit);
|
|
70735
|
+
for (const otherUnit of bucket) {
|
|
70736
|
+
if (targetUnit.id === otherUnit.id)
|
|
70737
|
+
continue;
|
|
70738
|
+
const [left, right] = orderedPair(targetUnit, otherUnit);
|
|
70739
|
+
const key = pairNumber(index, targetCanon, canonOf(index, otherUnit));
|
|
70740
|
+
if (seenPairs.has(key))
|
|
70741
|
+
continue;
|
|
70742
|
+
seenPairs.add(key);
|
|
70743
|
+
if (!filter.pair(left, right))
|
|
70744
|
+
continue;
|
|
70745
|
+
count++;
|
|
70746
|
+
if (count > limit)
|
|
70747
|
+
return true;
|
|
70748
|
+
}
|
|
70749
|
+
}
|
|
70750
|
+
return false;
|
|
70751
|
+
}
|
|
70752
|
+
function classifyBucket(index, bucket, maxBucketSize, filter) {
|
|
70753
|
+
if (bucket.length < 2)
|
|
70754
|
+
return "skip";
|
|
70755
|
+
if (filter && !bucket.some(filter.unit))
|
|
70756
|
+
return "skip";
|
|
70757
|
+
if (bucket.length > maxBucketSize) {
|
|
70758
|
+
if (!filter || filteredPairCountExceeds(index, bucket, maxBucketSize, filter))
|
|
70759
|
+
return "oversized";
|
|
70760
|
+
}
|
|
70761
|
+
return "pair";
|
|
70762
|
+
}
|
|
70763
|
+
function addBucketPairs(state, bucket, kind, filter) {
|
|
70764
|
+
const { index } = state;
|
|
70765
|
+
if (filter) {
|
|
70766
|
+
forEachFilteredBucketPair(index, bucket, filter, (left, right, key) => {
|
|
70767
|
+
addStrongEvidence(state, kind, left, right, key);
|
|
70768
|
+
});
|
|
70769
|
+
return;
|
|
70770
|
+
}
|
|
70771
|
+
const canons = new Int32Array(bucket.length);
|
|
70772
|
+
for (let i = 0; i < bucket.length; i++)
|
|
70773
|
+
canons[i] = canonOf(index, bucket[i]);
|
|
70774
|
+
for (let i = 0; i < bucket.length; i++) {
|
|
70775
|
+
for (let j = i + 1; j < bucket.length; j++) {
|
|
70776
|
+
addStrongEvidence(state, kind, bucket[i], bucket[j], pairNumber(index, canons[i], canons[j]));
|
|
70777
|
+
}
|
|
70778
|
+
}
|
|
70779
|
+
}
|
|
70780
|
+
async function addEvidenceBuckets(state, buckets, kind, options) {
|
|
70781
|
+
let oversizedBuckets = 0;
|
|
70782
|
+
for (const bucket of buckets.values()) {
|
|
70783
|
+
const verdict = classifyBucket(state.index, bucket, options.maxBucketSize, options.filter);
|
|
70784
|
+
if (verdict === "skip")
|
|
70785
|
+
continue;
|
|
70786
|
+
if (verdict === "oversized") {
|
|
70787
|
+
oversizedBuckets++;
|
|
70788
|
+
continue;
|
|
70789
|
+
}
|
|
70790
|
+
addBucketPairs(state, bucket, kind, options.filter);
|
|
70791
|
+
const pending = options.yieldPoint?.();
|
|
70792
|
+
if (pending)
|
|
70793
|
+
await pending;
|
|
70794
|
+
}
|
|
70795
|
+
return oversizedBuckets;
|
|
70796
|
+
}
|
|
70797
|
+
function hasEnoughFingerprints(sharedFingerprints, smallerConsideredCount) {
|
|
70798
|
+
if (!sharedFingerprints || !smallerConsideredCount)
|
|
70799
|
+
return false;
|
|
70800
|
+
return sharedFingerprints >= Math.max(2, Math.ceil(smallerConsideredCount * 0.25));
|
|
70801
|
+
}
|
|
70802
|
+
function eligibleFingerprintBuckets(state, buckets, options) {
|
|
70803
|
+
const eligible = [];
|
|
70804
|
+
let oversizedBuckets = 0;
|
|
70805
|
+
for (const bucket of buckets.values()) {
|
|
70806
|
+
const verdict = classifyBucket(state.index, bucket, options.maxBucketSize, options.filter);
|
|
70807
|
+
if (verdict === "skip")
|
|
70808
|
+
continue;
|
|
70809
|
+
if (verdict === "oversized") {
|
|
70810
|
+
oversizedBuckets++;
|
|
70811
|
+
continue;
|
|
70812
|
+
}
|
|
70813
|
+
eligible.push(bucket);
|
|
70814
|
+
}
|
|
70815
|
+
return { eligible, oversizedBuckets };
|
|
70816
|
+
}
|
|
70817
|
+
function layoutFingerprintBuckets(index, eligible) {
|
|
70818
|
+
const unitCount = index.units.length;
|
|
70819
|
+
const bucketCount = eligible.length;
|
|
70820
|
+
const bucketStart = new Int32Array(bucketCount + 1);
|
|
70821
|
+
const rankBase = new Float64Array(bucketCount);
|
|
70822
|
+
let total = 0;
|
|
70823
|
+
let rank = 0;
|
|
70824
|
+
for (let bucket = 0; bucket < bucketCount; bucket++) {
|
|
70825
|
+
const size = eligible[bucket].length;
|
|
70826
|
+
bucketStart[bucket] = total;
|
|
70827
|
+
rankBase[bucket] = rank;
|
|
70828
|
+
total += size;
|
|
70829
|
+
rank += size * size;
|
|
70830
|
+
}
|
|
70831
|
+
bucketStart[bucketCount] = total;
|
|
70832
|
+
const memberUnit = new Int32Array(total);
|
|
70833
|
+
const memberCanon = new Int32Array(total);
|
|
70834
|
+
const entryStart = new Int32Array(unitCount + 1);
|
|
70835
|
+
const consideredCount = new Int32Array(unitCount);
|
|
70836
|
+
const lastBucket = new Int32Array(unitCount).fill(-1);
|
|
70837
|
+
for (let bucket = 0, member = 0; bucket < bucketCount; bucket++) {
|
|
70838
|
+
for (const unit of eligible[bucket]) {
|
|
70839
|
+
const position = positionOf(index, unit);
|
|
70840
|
+
const unitCanon = index.canon[position];
|
|
70841
|
+
memberUnit[member] = position;
|
|
70842
|
+
memberCanon[member] = unitCanon;
|
|
70843
|
+
member++;
|
|
70844
|
+
entryStart[unitCanon + 1] = entryStart[unitCanon + 1] + 1;
|
|
70845
|
+
if (lastBucket[unitCanon] !== bucket) {
|
|
70846
|
+
lastBucket[unitCanon] = bucket;
|
|
70847
|
+
consideredCount[unitCanon] = consideredCount[unitCanon] + 1;
|
|
70848
|
+
}
|
|
70849
|
+
}
|
|
70850
|
+
}
|
|
70851
|
+
for (let unit = 0; unit < unitCount; unit++)
|
|
70852
|
+
entryStart[unit + 1] = entryStart[unit + 1] + entryStart[unit];
|
|
70853
|
+
const entryMember = new Int32Array(total);
|
|
70854
|
+
const entryBucket = new Int32Array(total);
|
|
70855
|
+
const nextEntry = entryStart.slice(0, unitCount);
|
|
70856
|
+
for (let bucket = 0; bucket < bucketCount; bucket++) {
|
|
70857
|
+
for (let member = bucketStart[bucket]; member < bucketStart[bucket + 1]; member++) {
|
|
70858
|
+
const unitCanon = memberCanon[member];
|
|
70859
|
+
const slot = nextEntry[unitCanon];
|
|
70860
|
+
nextEntry[unitCanon] = slot + 1;
|
|
70861
|
+
entryMember[slot] = member;
|
|
70862
|
+
entryBucket[slot] = bucket;
|
|
70863
|
+
}
|
|
70864
|
+
}
|
|
70865
|
+
return { bucketStart, rankBase, memberUnit, memberCanon, entryStart, entryMember, entryBucket, consideredCount };
|
|
70866
|
+
}
|
|
70867
|
+
function wholeProjectVisit(layout, units, first, second) {
|
|
70868
|
+
const { bucketStart, rankBase, memberUnit, entryStart, entryMember, entryBucket } = layout;
|
|
70869
|
+
const visits = [];
|
|
70870
|
+
let a = entryStart[first];
|
|
70871
|
+
const aEnd = entryStart[first + 1];
|
|
70872
|
+
let b = entryStart[second];
|
|
70873
|
+
const bEnd = entryStart[second + 1];
|
|
70874
|
+
while (a < aEnd && b < bEnd && visits.length < 2) {
|
|
70875
|
+
const bucketA = entryBucket[a];
|
|
70876
|
+
const bucketB = entryBucket[b];
|
|
70877
|
+
if (bucketA < bucketB) {
|
|
70878
|
+
a++;
|
|
70879
|
+
continue;
|
|
70880
|
+
}
|
|
70881
|
+
if (bucketB < bucketA) {
|
|
70882
|
+
b++;
|
|
70883
|
+
continue;
|
|
70884
|
+
}
|
|
70885
|
+
let aNext = a;
|
|
70886
|
+
while (aNext < aEnd && entryBucket[aNext] === bucketA)
|
|
70887
|
+
aNext++;
|
|
70888
|
+
let bNext = b;
|
|
70889
|
+
while (bNext < bEnd && entryBucket[bNext] === bucketA)
|
|
70890
|
+
bNext++;
|
|
70891
|
+
const start = bucketStart[bucketA];
|
|
70892
|
+
const size = bucketStart[bucketA + 1] - start;
|
|
70893
|
+
for (let x = a; x < aNext; x++) {
|
|
70894
|
+
for (let y = b; y < bNext; y++) {
|
|
70895
|
+
if (first === second && y <= x)
|
|
70896
|
+
continue;
|
|
70897
|
+
const low = Math.min(entryMember[x], entryMember[y]);
|
|
70898
|
+
const high = Math.max(entryMember[x], entryMember[y]);
|
|
70899
|
+
visits.push({ rank: rankBase[bucketA] + (low - start) * size + (high - start), low, high });
|
|
70900
|
+
}
|
|
70901
|
+
}
|
|
70902
|
+
a = aNext;
|
|
70903
|
+
b = bNext;
|
|
70904
|
+
}
|
|
70905
|
+
visits.sort((left2, right2) => left2.rank - right2.rank);
|
|
70906
|
+
const firstVisit = visits[0];
|
|
70907
|
+
const secondVisit = visits[1];
|
|
70908
|
+
const [left, right] = orderedPair(units[memberUnit[secondVisit.low]], units[memberUnit[secondVisit.high]]);
|
|
70909
|
+
return { rank: firstVisit.rank, left, right };
|
|
70910
|
+
}
|
|
70911
|
+
async function addProjectFingerprintPairs(state, layout, options) {
|
|
70912
|
+
const { index } = state;
|
|
70913
|
+
const unitCount = index.units.length;
|
|
70914
|
+
const { bucketStart, memberUnit, memberCanon, entryStart, entryMember, entryBucket } = layout;
|
|
70915
|
+
const selection = new FingerprintSelection(state, layout, void 0);
|
|
70916
|
+
const sharedBuckets = new Int32Array(unitCount);
|
|
70917
|
+
const touched = new Int32Array(unitCount);
|
|
70918
|
+
const sharesIds = index.hasSharedIds;
|
|
70919
|
+
const reportEvery = Math.max(1, Math.floor(unitCount / 100));
|
|
70920
|
+
for (let unit = 0; unit < unitCount; unit++) {
|
|
70921
|
+
const firstEntry = entryStart[unit];
|
|
70922
|
+
const lastEntry = entryStart[unit + 1];
|
|
70923
|
+
let touchedCount = 0;
|
|
70924
|
+
const lowestPartner = sharesIds ? unit : 0;
|
|
70925
|
+
for (let slot = firstEntry; slot < lastEntry; slot++) {
|
|
70926
|
+
const member = entryMember[slot];
|
|
70927
|
+
const bucket = entryBucket[slot];
|
|
70928
|
+
const bucketEnd = bucketStart[bucket + 1];
|
|
70929
|
+
for (let other = member + 1; other < bucketEnd; other++) {
|
|
70930
|
+
const partner = memberCanon[other];
|
|
70931
|
+
if (partner < lowestPartner)
|
|
70932
|
+
continue;
|
|
70933
|
+
const shared = sharedBuckets[partner];
|
|
70934
|
+
if (!shared)
|
|
70935
|
+
touched[touchedCount++] = partner;
|
|
70936
|
+
sharedBuckets[partner] = shared + 1;
|
|
70937
|
+
}
|
|
70938
|
+
if (sharesIds && memberUnit[member] !== unit) {
|
|
70939
|
+
for (let other = bucketStart[bucket]; other < member; other++) {
|
|
70940
|
+
const partner = memberCanon[other];
|
|
70941
|
+
if (partner <= unit)
|
|
70942
|
+
continue;
|
|
70943
|
+
const shared = sharedBuckets[partner];
|
|
70944
|
+
if (!shared)
|
|
70945
|
+
touched[touchedCount++] = partner;
|
|
70946
|
+
sharedBuckets[partner] = shared + 1;
|
|
70947
|
+
}
|
|
70948
|
+
}
|
|
70949
|
+
}
|
|
70950
|
+
for (let at = 0; at < touchedCount; at++) {
|
|
70951
|
+
const partner = touched[at];
|
|
70952
|
+
const count = sharedBuckets[partner];
|
|
70953
|
+
sharedBuckets[partner] = 0;
|
|
70954
|
+
selection.consider(unit, partner, count);
|
|
70955
|
+
}
|
|
70956
|
+
if (unit % reportEvery === 0)
|
|
70957
|
+
options.onFingerprintProgress?.(unit + 1, unitCount);
|
|
70958
|
+
const pending = options.yieldPoint?.();
|
|
70959
|
+
if (pending)
|
|
70960
|
+
await pending;
|
|
70961
|
+
}
|
|
70962
|
+
options.onFingerprintProgress?.(unitCount, unitCount);
|
|
70963
|
+
selection.admit((first, second) => wholeProjectVisit(layout, index.units, first, second));
|
|
70964
|
+
}
|
|
70965
|
+
function targetedVisit(layout, units, targets, first, second) {
|
|
70966
|
+
const { bucketStart, rankBase, memberUnit, entryStart, entryMember, entryBucket } = layout;
|
|
70967
|
+
let a = entryStart[first];
|
|
70968
|
+
const aEnd = entryStart[first + 1];
|
|
70969
|
+
let b = entryStart[second];
|
|
70970
|
+
const bEnd = entryStart[second + 1];
|
|
70971
|
+
const firstIsTarget = targets.isTarget[first] === 1;
|
|
70972
|
+
const secondIsTarget = targets.isTarget[second] === 1;
|
|
70973
|
+
let firstRank = -1;
|
|
70974
|
+
while (a < aEnd && b < bEnd) {
|
|
70975
|
+
const bucket = entryBucket[a];
|
|
70976
|
+
if (bucket < entryBucket[b]) {
|
|
70977
|
+
a++;
|
|
70978
|
+
continue;
|
|
70979
|
+
}
|
|
70980
|
+
if (entryBucket[b] < bucket) {
|
|
70981
|
+
b++;
|
|
70982
|
+
continue;
|
|
70983
|
+
}
|
|
70984
|
+
const slotA = entryMember[a];
|
|
70985
|
+
const slotB = entryMember[b];
|
|
70986
|
+
const walkedFromA = firstIsTarget && (!secondIsTarget || slotA < slotB);
|
|
70987
|
+
const targetSlot = walkedFromA ? slotA : slotB;
|
|
70988
|
+
const otherSlot = walkedFromA ? slotB : slotA;
|
|
70989
|
+
if (firstRank < 0) {
|
|
70990
|
+
const start = bucketStart[bucket];
|
|
70991
|
+
const size = bucketStart[bucket + 1] - start;
|
|
70992
|
+
firstRank = rankBase[bucket] + targets.before[targetSlot] * size + (otherSlot - start);
|
|
70993
|
+
} else {
|
|
70994
|
+
const [left, right] = orderedPair(units[memberUnit[targetSlot]], units[memberUnit[otherSlot]]);
|
|
70995
|
+
return { rank: firstRank, left, right };
|
|
70996
|
+
}
|
|
70997
|
+
while (a < aEnd && entryBucket[a] === bucket)
|
|
70998
|
+
a++;
|
|
70999
|
+
while (b < bEnd && entryBucket[b] === bucket)
|
|
71000
|
+
b++;
|
|
71001
|
+
}
|
|
71002
|
+
throw new Error("A candidate pair from shared fingerprints shares fewer than two buckets.");
|
|
71003
|
+
}
|
|
71004
|
+
function addTargetedFingerprintPairs(state, layout, filter) {
|
|
71005
|
+
const { index } = state;
|
|
71006
|
+
const unitCount = index.units.length;
|
|
71007
|
+
const { bucketStart, memberCanon, entryStart, entryBucket } = layout;
|
|
71008
|
+
const bucketCount = bucketStart.length - 1;
|
|
71009
|
+
const isTarget = new Uint8Array(unitCount);
|
|
71010
|
+
for (let unit = 0; unit < unitCount; unit++) {
|
|
71011
|
+
if (entryStart[unit + 1] > entryStart[unit] && filter.unit(index.units[unit]))
|
|
71012
|
+
isTarget[unit] = 1;
|
|
71013
|
+
}
|
|
71014
|
+
const before = new Int32Array(memberCanon.length);
|
|
71015
|
+
for (let bucket = 0; bucket < bucketCount; bucket++) {
|
|
71016
|
+
let targetsSoFar = 0;
|
|
71017
|
+
for (let member = bucketStart[bucket]; member < bucketStart[bucket + 1]; member++) {
|
|
71018
|
+
before[member] = targetsSoFar;
|
|
71019
|
+
targetsSoFar += isTarget[memberCanon[member]];
|
|
71020
|
+
}
|
|
71021
|
+
}
|
|
71022
|
+
const selection = new FingerprintSelection(state, layout, filter.pair);
|
|
71023
|
+
const sharedBuckets = new Int32Array(unitCount);
|
|
71024
|
+
const touched = new Int32Array(unitCount);
|
|
71025
|
+
const countedIn = index.hasSharedIds ? new Int32Array(unitCount) : void 0;
|
|
71026
|
+
let walk = 0;
|
|
71027
|
+
for (let target = 0; target < unitCount; target++) {
|
|
71028
|
+
if (!isTarget[target])
|
|
71029
|
+
continue;
|
|
71030
|
+
let touchedCount = 0;
|
|
71031
|
+
let previousBucket = -1;
|
|
71032
|
+
for (let slot = entryStart[target]; slot < entryStart[target + 1]; slot++) {
|
|
71033
|
+
const bucket = entryBucket[slot];
|
|
71034
|
+
if (bucket === previousBucket)
|
|
71035
|
+
continue;
|
|
71036
|
+
previousBucket = bucket;
|
|
71037
|
+
walk++;
|
|
71038
|
+
for (let member = bucketStart[bucket]; member < bucketStart[bucket + 1]; member++) {
|
|
71039
|
+
const partner = memberCanon[member];
|
|
71040
|
+
if (partner === target || partner < target && isTarget[partner])
|
|
71041
|
+
continue;
|
|
71042
|
+
if (countedIn) {
|
|
71043
|
+
if (countedIn[partner] === walk)
|
|
71044
|
+
continue;
|
|
71045
|
+
countedIn[partner] = walk;
|
|
71046
|
+
}
|
|
71047
|
+
const shared = sharedBuckets[partner];
|
|
71048
|
+
if (!shared)
|
|
71049
|
+
touched[touchedCount++] = partner;
|
|
71050
|
+
sharedBuckets[partner] = shared + 1;
|
|
71051
|
+
}
|
|
71052
|
+
}
|
|
71053
|
+
for (let at = 0; at < touchedCount; at++) {
|
|
71054
|
+
const partner = touched[at];
|
|
71055
|
+
const count = sharedBuckets[partner];
|
|
71056
|
+
sharedBuckets[partner] = 0;
|
|
71057
|
+
selection.consider(target, partner, count);
|
|
71058
|
+
}
|
|
71059
|
+
}
|
|
71060
|
+
selection.admit((first, second) => targetedVisit(layout, index.units, { isTarget, before }, first, second));
|
|
71061
|
+
}
|
|
71062
|
+
function normalizeSimilarityIndex(value) {
|
|
71063
|
+
if (!Number.isFinite(value))
|
|
71064
|
+
return void 0;
|
|
71065
|
+
const bounded = Math.max(0, Math.min(100, Math.round(value)));
|
|
71066
|
+
if (bounded < MIN_SIMILARITY_HINT_INDEX)
|
|
71067
|
+
return void 0;
|
|
71068
|
+
return bounded;
|
|
71069
|
+
}
|
|
71070
|
+
function normalizeSimilarityHintFile(file2, projectRoot) {
|
|
71071
|
+
try {
|
|
71072
|
+
return normalizeDetectionFile(file2, projectRoot);
|
|
71073
|
+
} catch {
|
|
71074
|
+
return void 0;
|
|
71075
|
+
}
|
|
71076
|
+
}
|
|
71077
|
+
function addSimilarityHintPair(state, left, right, similarityIndex) {
|
|
71078
|
+
const key = pairNumber(state.index, canonOf(state.index, left), canonOf(state.index, right));
|
|
71079
|
+
const evidence = takePair(state, key, left, right);
|
|
71080
|
+
if (evidence)
|
|
71081
|
+
evidence.gitSimilarity = Math.max(evidence.gitSimilarity ?? 0, similarityIndex);
|
|
71082
|
+
}
|
|
71083
|
+
function similarityHintPairCountExceeds(leftUnits, rightUnits, limit, pairFilter) {
|
|
71084
|
+
let count = 0;
|
|
71085
|
+
for (const leftUnit of leftUnits) {
|
|
71086
|
+
for (const rightUnit of rightUnits) {
|
|
71087
|
+
if (leftUnit.languageId !== rightUnit.languageId)
|
|
71088
|
+
continue;
|
|
71089
|
+
const [left, right] = orderedPair(leftUnit, rightUnit);
|
|
71090
|
+
if (pairFilter && !pairFilter(left, right))
|
|
71091
|
+
continue;
|
|
71092
|
+
count++;
|
|
71093
|
+
if (count > limit)
|
|
71094
|
+
return true;
|
|
71095
|
+
}
|
|
71096
|
+
}
|
|
71097
|
+
return false;
|
|
71098
|
+
}
|
|
71099
|
+
function similarityAlignmentKey(unit) {
|
|
71100
|
+
return [unit.languageId, unit.kind, unit.symbolKind ?? ""].join(":");
|
|
71101
|
+
}
|
|
71102
|
+
function addAlignedSimilarityHintPairs(state, leftUnits, rightUnits, similarityIndex, maxPairs, pairFilter) {
|
|
71103
|
+
const rightByKey = /* @__PURE__ */ new Map();
|
|
71104
|
+
for (const unit of rightUnits) {
|
|
71105
|
+
const key = similarityAlignmentKey(unit);
|
|
71106
|
+
const bucket = rightByKey.get(key);
|
|
71107
|
+
if (bucket)
|
|
71108
|
+
bucket.push(unit);
|
|
71109
|
+
else
|
|
71110
|
+
rightByKey.set(key, [unit]);
|
|
71111
|
+
}
|
|
71112
|
+
for (const bucket of rightByKey.values()) {
|
|
71113
|
+
bucket.sort(compareUnitRefs);
|
|
71114
|
+
}
|
|
71115
|
+
const leftByKey = /* @__PURE__ */ new Map();
|
|
71116
|
+
for (const unit of leftUnits) {
|
|
71117
|
+
const key = similarityAlignmentKey(unit);
|
|
71118
|
+
const bucket = leftByKey.get(key);
|
|
71119
|
+
if (bucket)
|
|
71120
|
+
bucket.push(unit);
|
|
71121
|
+
else
|
|
71122
|
+
leftByKey.set(key, [unit]);
|
|
71123
|
+
}
|
|
71124
|
+
for (const bucket of leftByKey.values()) {
|
|
71125
|
+
bucket.sort(compareUnitRefs);
|
|
71126
|
+
}
|
|
71127
|
+
const seenPairs = /* @__PURE__ */ new Set();
|
|
71128
|
+
let addedPairs = 0;
|
|
71129
|
+
for (const [key, sortedLeftUnits] of Array.from(leftByKey.entries()).sort(([left], [right]) => left.localeCompare(right))) {
|
|
71130
|
+
const sortedRightUnits = rightByKey.get(key);
|
|
71131
|
+
if (!sortedRightUnits?.length)
|
|
71132
|
+
continue;
|
|
71133
|
+
const limit = Math.min(sortedLeftUnits.length, sortedRightUnits.length);
|
|
71134
|
+
for (let index = 0; index < limit; index++) {
|
|
71135
|
+
if (addedPairs >= maxPairs)
|
|
71136
|
+
return;
|
|
71137
|
+
const [left, right] = orderedPair(sortedLeftUnits[index], sortedRightUnits[index]);
|
|
71138
|
+
const pairId = pairNumber(state.index, canonOf(state.index, left), canonOf(state.index, right));
|
|
71139
|
+
if (seenPairs.has(pairId))
|
|
71140
|
+
continue;
|
|
71141
|
+
seenPairs.add(pairId);
|
|
71142
|
+
if (pairFilter && !pairFilter(left, right))
|
|
71143
|
+
continue;
|
|
71144
|
+
addSimilarityHintPair(state, left, right, similarityIndex);
|
|
71145
|
+
addedPairs++;
|
|
71146
|
+
}
|
|
71147
|
+
}
|
|
71148
|
+
}
|
|
71149
|
+
function addSimilarityHintPairs(state, similarityHints, projectRoot, maxBucketSize, pairFilter) {
|
|
71150
|
+
if (!similarityHints?.length)
|
|
71151
|
+
return 0;
|
|
71152
|
+
const unitsByFile = /* @__PURE__ */ new Map();
|
|
71153
|
+
for (const unit of state.index.units) {
|
|
71154
|
+
const bucket = unitsByFile.get(unit.absoluteFile);
|
|
71155
|
+
if (bucket) {
|
|
71156
|
+
bucket.push(unit);
|
|
71157
|
+
} else {
|
|
71158
|
+
unitsByFile.set(unit.absoluteFile, [unit]);
|
|
71159
|
+
}
|
|
71160
|
+
}
|
|
71161
|
+
let oversizedHints = 0;
|
|
71162
|
+
for (const hint of similarityHints) {
|
|
71163
|
+
const similarityIndex = normalizeSimilarityIndex(hint.similarityIndex);
|
|
71164
|
+
if (similarityIndex === void 0)
|
|
71165
|
+
continue;
|
|
71166
|
+
const leftFile = normalizeSimilarityHintFile(hint.leftFile, projectRoot);
|
|
71167
|
+
const rightFile = normalizeSimilarityHintFile(hint.rightFile, projectRoot);
|
|
71168
|
+
if (!leftFile || !rightFile || leftFile === rightFile)
|
|
71169
|
+
continue;
|
|
71170
|
+
const leftUnits = unitsByFile.get(leftFile);
|
|
71171
|
+
const rightUnits = unitsByFile.get(rightFile);
|
|
71172
|
+
if (!leftUnits?.length || !rightUnits?.length)
|
|
71173
|
+
continue;
|
|
71174
|
+
if (similarityHintPairCountExceeds(leftUnits, rightUnits, maxBucketSize, pairFilter)) {
|
|
71175
|
+
oversizedHints++;
|
|
71176
|
+
addAlignedSimilarityHintPairs(state, leftUnits, rightUnits, similarityIndex, maxBucketSize, pairFilter);
|
|
71177
|
+
continue;
|
|
71178
|
+
}
|
|
71179
|
+
for (const leftUnit of leftUnits) {
|
|
71180
|
+
for (const rightUnit of rightUnits) {
|
|
71181
|
+
if (leftUnit.languageId !== rightUnit.languageId)
|
|
71182
|
+
continue;
|
|
71183
|
+
const [left, right] = orderedPair(leftUnit, rightUnit);
|
|
71184
|
+
if (pairFilter && !pairFilter(left, right))
|
|
71185
|
+
continue;
|
|
71186
|
+
addSimilarityHintPair(state, left, right, similarityIndex);
|
|
71187
|
+
}
|
|
71188
|
+
}
|
|
71189
|
+
}
|
|
71190
|
+
return oversizedHints;
|
|
71191
|
+
}
|
|
71192
|
+
async function buildCandidatePairs(preparedBuckets, options) {
|
|
71193
|
+
const state = {
|
|
71194
|
+
index: createUnitIndex(preparedBuckets.units),
|
|
71195
|
+
crossFileOnly: options.crossFileOnly,
|
|
71196
|
+
pairs: /* @__PURE__ */ new Map(),
|
|
71197
|
+
unscorable: /* @__PURE__ */ new Set(),
|
|
71198
|
+
limit: options.maxCandidatePairs,
|
|
71199
|
+
skipped: 0
|
|
71200
|
+
};
|
|
71201
|
+
let oversizedBuckets = 0;
|
|
71202
|
+
oversizedBuckets += await addEvidenceBuckets(state, preparedBuckets.rawHashBuckets, "rawHash", options);
|
|
71203
|
+
oversizedBuckets += await addEvidenceBuckets(state, preparedBuckets.normalizedHashBuckets, "normalizedHash", options);
|
|
71204
|
+
oversizedBuckets += await addEvidenceBuckets(state, preparedBuckets.astShapeBuckets, "astShape", options);
|
|
71205
|
+
oversizedBuckets += addSimilarityHintPairs(state, options.similarityHints, options.projectRoot, options.maxBucketSize, options.filter?.pair);
|
|
71206
|
+
const fingerprints = eligibleFingerprintBuckets(state, preparedBuckets.signatureBuckets, options);
|
|
71207
|
+
oversizedBuckets += fingerprints.oversizedBuckets;
|
|
71208
|
+
const layout = layoutFingerprintBuckets(state.index, fingerprints.eligible);
|
|
71209
|
+
if (options.filter) {
|
|
71210
|
+
addTargetedFingerprintPairs(state, layout, options.filter);
|
|
71211
|
+
} else {
|
|
71212
|
+
await addProjectFingerprintPairs(state, layout, options);
|
|
71213
|
+
}
|
|
71214
|
+
return {
|
|
71215
|
+
pairs: state.pairs,
|
|
71216
|
+
oversizedBuckets,
|
|
71217
|
+
skippedPairs: state.skipped,
|
|
71218
|
+
unscorablePairs: state.unscorable.size,
|
|
71219
|
+
overlappingPairs: state.crossFileOnly ? 0 : state.unscorable.size
|
|
71220
|
+
};
|
|
71221
|
+
}
|
|
71222
|
+
var MIN_SIMILARITY_HINT_INDEX, BestPairs, FingerprintSelection;
|
|
71223
|
+
var init_candidates = __esm({
|
|
71224
|
+
"dist/duplicates/candidates.js"() {
|
|
71225
|
+
"use strict";
|
|
71226
|
+
init_collections();
|
|
71227
|
+
init_scoring();
|
|
71228
|
+
init_units();
|
|
71229
|
+
MIN_SIMILARITY_HINT_INDEX = 80;
|
|
71230
|
+
BestPairs = class {
|
|
71231
|
+
capacity;
|
|
71232
|
+
size = 0;
|
|
71233
|
+
priority;
|
|
71234
|
+
first;
|
|
71235
|
+
second;
|
|
71236
|
+
matches;
|
|
71237
|
+
constructor(capacity) {
|
|
71238
|
+
this.capacity = capacity;
|
|
71239
|
+
const initial = Math.min(capacity, 1024);
|
|
71240
|
+
this.priority = new Float64Array(initial);
|
|
71241
|
+
this.first = new Int32Array(initial);
|
|
71242
|
+
this.second = new Int32Array(initial);
|
|
71243
|
+
this.matches = new Int32Array(initial);
|
|
71244
|
+
}
|
|
71245
|
+
/** Better means more of the smaller unit's fingerprints shared, then the earlier unit ids. */
|
|
71246
|
+
isWorse(a, b) {
|
|
71247
|
+
if (this.priority[a] !== this.priority[b])
|
|
71248
|
+
return this.priority[a] < this.priority[b];
|
|
71249
|
+
if (this.first[a] !== this.first[b])
|
|
71250
|
+
return this.first[a] > this.first[b];
|
|
71251
|
+
return this.second[a] > this.second[b];
|
|
71252
|
+
}
|
|
71253
|
+
swap(a, b) {
|
|
71254
|
+
const priority = this.priority[a];
|
|
71255
|
+
this.priority[a] = this.priority[b];
|
|
71256
|
+
this.priority[b] = priority;
|
|
71257
|
+
const first = this.first[a];
|
|
71258
|
+
this.first[a] = this.first[b];
|
|
71259
|
+
this.first[b] = first;
|
|
71260
|
+
const second = this.second[a];
|
|
71261
|
+
this.second[a] = this.second[b];
|
|
71262
|
+
this.second[b] = second;
|
|
71263
|
+
const matches = this.matches[a];
|
|
71264
|
+
this.matches[a] = this.matches[b];
|
|
71265
|
+
this.matches[b] = matches;
|
|
71266
|
+
}
|
|
71267
|
+
grow() {
|
|
71268
|
+
const next = Math.min(this.capacity, this.priority.length * 2);
|
|
71269
|
+
const priority = new Float64Array(next);
|
|
71270
|
+
priority.set(this.priority);
|
|
71271
|
+
this.priority = priority;
|
|
71272
|
+
for (const name of ["first", "second", "matches"]) {
|
|
71273
|
+
const grown = new Int32Array(next);
|
|
71274
|
+
grown.set(this[name]);
|
|
71275
|
+
this[name] = grown;
|
|
71276
|
+
}
|
|
71277
|
+
}
|
|
71278
|
+
siftUp(start) {
|
|
71279
|
+
let slot = start;
|
|
71280
|
+
while (slot > 0) {
|
|
71281
|
+
const parent = slot - 1 >> 1;
|
|
71282
|
+
if (!this.isWorse(slot, parent))
|
|
71283
|
+
return;
|
|
71284
|
+
this.swap(slot, parent);
|
|
71285
|
+
slot = parent;
|
|
71286
|
+
}
|
|
71287
|
+
}
|
|
71288
|
+
siftDown(start) {
|
|
71289
|
+
let slot = start;
|
|
71290
|
+
for (; ; ) {
|
|
71291
|
+
const left = slot * 2 + 1;
|
|
71292
|
+
const right = left + 1;
|
|
71293
|
+
let worst = slot;
|
|
71294
|
+
if (left < this.size && this.isWorse(left, worst))
|
|
71295
|
+
worst = left;
|
|
71296
|
+
if (right < this.size && this.isWorse(right, worst))
|
|
71297
|
+
worst = right;
|
|
71298
|
+
if (worst === slot)
|
|
71299
|
+
return;
|
|
71300
|
+
this.swap(slot, worst);
|
|
71301
|
+
slot = worst;
|
|
71302
|
+
}
|
|
71303
|
+
}
|
|
71304
|
+
/** Whether a pair ranks above the worst pair kept, by the same order `isWorse` uses. */
|
|
71305
|
+
beatsWorst(priority, first, second) {
|
|
71306
|
+
if (priority !== this.priority[0])
|
|
71307
|
+
return priority > this.priority[0];
|
|
71308
|
+
if (first !== this.first[0])
|
|
71309
|
+
return first < this.first[0];
|
|
71310
|
+
return second < this.second[0];
|
|
71311
|
+
}
|
|
71312
|
+
offer(priority, first, second, matches) {
|
|
71313
|
+
if (!this.capacity)
|
|
71314
|
+
return;
|
|
71315
|
+
if (this.size === this.capacity) {
|
|
71316
|
+
if (!this.beatsWorst(priority, first, second))
|
|
71317
|
+
return;
|
|
71318
|
+
this.priority[0] = priority;
|
|
71319
|
+
this.first[0] = first;
|
|
71320
|
+
this.second[0] = second;
|
|
71321
|
+
this.matches[0] = matches;
|
|
71322
|
+
this.siftDown(0);
|
|
71323
|
+
return;
|
|
71324
|
+
}
|
|
71325
|
+
if (this.size === this.priority.length)
|
|
71326
|
+
this.grow();
|
|
71327
|
+
const slot = this.size++;
|
|
71328
|
+
this.priority[slot] = priority;
|
|
71329
|
+
this.first[slot] = first;
|
|
71330
|
+
this.second[slot] = second;
|
|
71331
|
+
this.matches[slot] = matches;
|
|
71332
|
+
this.siftUp(slot);
|
|
71333
|
+
}
|
|
71334
|
+
entries() {
|
|
71335
|
+
const entries = [];
|
|
71336
|
+
for (let slot = 0; slot < this.size; slot++) {
|
|
71337
|
+
entries.push({ first: this.first[slot], second: this.second[slot], matches: this.matches[slot] });
|
|
71338
|
+
}
|
|
71339
|
+
return entries;
|
|
71340
|
+
}
|
|
71341
|
+
};
|
|
71342
|
+
FingerprintSelection = class {
|
|
71343
|
+
state;
|
|
71344
|
+
layout;
|
|
71345
|
+
pairFilter;
|
|
71346
|
+
best;
|
|
71347
|
+
qualifying = 0;
|
|
71348
|
+
constructor(state, layout, pairFilter) {
|
|
71349
|
+
this.state = state;
|
|
71350
|
+
this.layout = layout;
|
|
71351
|
+
this.pairFilter = pairFilter;
|
|
71352
|
+
this.best = new BestPairs(Math.max(0, state.limit - state.pairs.size));
|
|
71353
|
+
}
|
|
71354
|
+
/** Takes two canonical units that share `count` eligible buckets; fewer than two cannot qualify. */
|
|
71355
|
+
consider(first, second, count) {
|
|
71356
|
+
if (count < 2)
|
|
71357
|
+
return;
|
|
71358
|
+
const { index, pairs } = this.state;
|
|
71359
|
+
const smaller = Math.min(this.layout.consideredCount[first], this.layout.consideredCount[second]);
|
|
71360
|
+
if (!hasEnoughFingerprints(count, smaller))
|
|
71361
|
+
return;
|
|
71362
|
+
const firstUnit = index.units[first];
|
|
71363
|
+
const secondUnit = index.units[second];
|
|
71364
|
+
if (this.pairFilter) {
|
|
71365
|
+
const [left, right] = orderedPair(firstUnit, secondUnit);
|
|
71366
|
+
if (!this.pairFilter(left, right))
|
|
71367
|
+
return;
|
|
71368
|
+
}
|
|
71369
|
+
const key = pairNumber(index, first, second);
|
|
71370
|
+
const existing = pairs.get(key);
|
|
71371
|
+
if (existing) {
|
|
71372
|
+
existing.signatureMatches = count;
|
|
71373
|
+
existing.signature = true;
|
|
71374
|
+
return;
|
|
71375
|
+
}
|
|
71376
|
+
if (!isScorablePair(firstUnit, secondUnit, this.state.crossFileOnly)) {
|
|
71377
|
+
tallyUnscorable(this.state, key);
|
|
71378
|
+
return;
|
|
71379
|
+
}
|
|
71380
|
+
this.qualifying++;
|
|
71381
|
+
this.best.offer(count / smaller, Math.min(first, second), Math.max(first, second), count);
|
|
71382
|
+
}
|
|
71383
|
+
/** Adds the kept pairs in the order a walk of the buckets would first have met them, and counts the rest skipped. */
|
|
71384
|
+
admit(visitOf) {
|
|
71385
|
+
const { index, pairs } = this.state;
|
|
71386
|
+
const admissions = this.best.entries().map(({ first, second, matches }) => ({
|
|
71387
|
+
...visitOf(first, second),
|
|
71388
|
+
key: pairNumber(index, first, second),
|
|
71389
|
+
count: matches
|
|
71390
|
+
}));
|
|
71391
|
+
admissions.sort((left, right) => left.rank - right.rank);
|
|
71392
|
+
for (const admission of admissions) {
|
|
71393
|
+
pairs.set(admission.key, {
|
|
71394
|
+
left: admission.left,
|
|
71395
|
+
right: admission.right,
|
|
71396
|
+
rawHash: false,
|
|
71397
|
+
normalizedHash: false,
|
|
71398
|
+
astShape: false,
|
|
71399
|
+
signature: true,
|
|
71400
|
+
signatureMatches: admission.count
|
|
71401
|
+
});
|
|
71402
|
+
}
|
|
71403
|
+
this.state.skipped += this.qualifying - admissions.length;
|
|
71404
|
+
}
|
|
71405
|
+
};
|
|
71406
|
+
}
|
|
71407
|
+
});
|
|
71408
|
+
|
|
70866
71409
|
// dist/duplicates.js
|
|
70867
71410
|
async function findDuplicates(index, options = {}) {
|
|
70868
71411
|
const releaseDuplicateUnitCache = leaseDuplicateUnitCacheForIndex2(index);
|
|
@@ -70874,15 +71417,14 @@ async function findDuplicates(index, options = {}) {
|
|
|
70874
71417
|
releaseDuplicateUnitCache();
|
|
70875
71418
|
}
|
|
70876
71419
|
}
|
|
70877
|
-
|
|
70878
|
-
|
|
70879
|
-
|
|
70880
|
-
|
|
70881
|
-
|
|
70882
|
-
|
|
70883
|
-
|
|
70884
|
-
const
|
|
70885
|
-
const collectedUnits = preparedData?.collectedUnits ?? await collectDuplicateUnits2(index, collectionOptions);
|
|
71420
|
+
function omittedCandidatePairs(uncomparedPairs, budget) {
|
|
71421
|
+
return uncomparedPairs + (budget?.skipped ?? 0);
|
|
71422
|
+
}
|
|
71423
|
+
function foundCandidatePairs(keptPairs, unscorablePairs, maxCandidatePairs) {
|
|
71424
|
+
return Math.min(maxCandidatePairs, keptPairs + unscorablePairs);
|
|
71425
|
+
}
|
|
71426
|
+
async function collectCandidatePairs(index, options, collectionOptions, preparedData, limits, progress) {
|
|
71427
|
+
const collectedUnits = preparedData?.collectedUnits ?? await collectDuplicateUnits2(index, collectionOptions, progress);
|
|
70886
71428
|
let units = collectedUnits.units;
|
|
70887
71429
|
let belowThresholdUnits = collectedUnits.belowThresholdUnits;
|
|
70888
71430
|
let candidateBuckets = preparedData?.preparedBuckets;
|
|
@@ -70896,13 +71438,44 @@ async function findDuplicatesWithOpenDuplicateUnitCache(index, options = {}, pre
|
|
|
70896
71438
|
belowThresholdUnits += collectedUnits.belowThresholdUnitsByFile.get(file2) ?? 0;
|
|
70897
71439
|
}
|
|
70898
71440
|
}
|
|
70899
|
-
|
|
70900
|
-
const { pairs, oversizedBuckets } =
|
|
71441
|
+
progress?.stage(DUPLICATE_STAGE_PAIRS);
|
|
71442
|
+
const { pairs, oversizedBuckets, skippedPairs, unscorablePairs, overlappingPairs } = await buildCandidatePairs2(candidateBuckets ?? prepareDuplicateCandidateBuckets2(units), {
|
|
71443
|
+
...limits,
|
|
71444
|
+
similarityHints: options.similarityHints,
|
|
71445
|
+
projectRoot: collectionOptions.projectRoot,
|
|
71446
|
+
onFingerprintProgress: progress ? (current, total) => progress.stage(DUPLICATE_STAGE_PAIRS, current, total, "unit") : void 0,
|
|
71447
|
+
yieldPoint: progress?.yieldPoint
|
|
71448
|
+
});
|
|
71449
|
+
return {
|
|
71450
|
+
unitCount: units.length,
|
|
71451
|
+
belowThresholdUnits,
|
|
71452
|
+
pairs,
|
|
71453
|
+
oversizedBuckets,
|
|
71454
|
+
skippedPairs,
|
|
71455
|
+
unscorablePairs,
|
|
71456
|
+
overlappingPairs
|
|
71457
|
+
};
|
|
71458
|
+
}
|
|
71459
|
+
async function findDuplicatesWithOpenDuplicateUnitCache(index, options = {}, preparedData) {
|
|
71460
|
+
const collectionOptions = duplicateUnitCollectionOptions(index, options);
|
|
71461
|
+
const maxBucketSize = normalizePositiveIntegerOption2(options.maxBucketSize, "maxBucketSize", DEFAULT_MAX_BUCKET_SIZE2);
|
|
71462
|
+
const maxCandidatePairs = normalizeMaxCandidatePairsOption2(options.maxCandidatePairs);
|
|
71463
|
+
const maxPairs = options.maxPairs === void 0 ? Number.POSITIVE_INFINITY : normalizeNonNegativeIntegerOption2(options.maxPairs, "maxPairs", DEFAULT_LIMIT2);
|
|
71464
|
+
const crossFileOnly = options.crossFileOnly ?? !(options.includeSameFile ?? false);
|
|
71465
|
+
const minConfidence = normalizeConfidence2(options.minConfidence);
|
|
71466
|
+
const limit = normalizeNonNegativeIntegerOption2(options.limit, "limit", DEFAULT_LIMIT2);
|
|
71467
|
+
const progress = createDuplicateProgress(options.onProgress, options.progressStartedAt);
|
|
71468
|
+
progress?.stage(preparedData ? DUPLICATE_STAGE_PAIRS : DUPLICATE_STAGE_UNITS);
|
|
71469
|
+
const { unitCount, belowThresholdUnits, pairs, oversizedBuckets, skippedPairs, unscorablePairs, overlappingPairs } = await collectCandidatePairs(index, options, collectionOptions, preparedData, { maxBucketSize, maxCandidatePairs, crossFileOnly }, progress);
|
|
71470
|
+
const scorablePairCount = pairs.size;
|
|
71471
|
+
const candidatePairCount = foundCandidatePairs(scorablePairCount, unscorablePairs, maxCandidatePairs);
|
|
71472
|
+
const candidatePairBudget = skippedPairs ? { limit: maxCandidatePairs, skipped: skippedPairs } : void 0;
|
|
70901
71473
|
if (options.countOnly) {
|
|
70902
|
-
const groupCount = countCandidateDuplicateGroups(pairs
|
|
71474
|
+
const groupCount = countCandidateDuplicateGroups(pairs);
|
|
71475
|
+
progress?.complete(unitCount);
|
|
70903
71476
|
return {
|
|
70904
71477
|
schemaVersion: 3,
|
|
70905
|
-
units:
|
|
71478
|
+
units: unitCount,
|
|
70906
71479
|
groups: [],
|
|
70907
71480
|
omittedCounts: {
|
|
70908
71481
|
groups: groupCount,
|
|
@@ -70910,24 +71483,28 @@ async function findDuplicatesWithOpenDuplicateUnitCache(index, options = {}, pre
|
|
|
70910
71483
|
oversizedBuckets,
|
|
70911
71484
|
belowThresholdUnits,
|
|
70912
71485
|
overlappingPairs: 0,
|
|
70913
|
-
candidatePairs:
|
|
71486
|
+
candidatePairs: omittedCandidatePairs(pairs.size, candidatePairBudget)
|
|
70914
71487
|
},
|
|
70915
71488
|
stats: {
|
|
70916
71489
|
comparedPairs: 0,
|
|
70917
|
-
candidatePairs:
|
|
71490
|
+
candidatePairs: candidatePairCount,
|
|
71491
|
+
...candidatePairBudget ? { candidatePairBudget } : {}
|
|
70918
71492
|
}
|
|
70919
71493
|
};
|
|
70920
71494
|
}
|
|
70921
71495
|
const suggestions = [];
|
|
70922
|
-
let overlappingPairs = 0;
|
|
70923
71496
|
let comparedPairs = 0;
|
|
70924
71497
|
let skippedCandidatePairs = 0;
|
|
71498
|
+
progress?.stage(DUPLICATE_STAGE_SCORING, 0, scorablePairCount, "pair");
|
|
71499
|
+
const reportEvery = Math.max(1, Math.floor(scorablePairCount / 100));
|
|
71500
|
+
let visitedPairs = 0;
|
|
70925
71501
|
for (const evidence of pairs.values()) {
|
|
70926
|
-
|
|
70927
|
-
|
|
70928
|
-
|
|
70929
|
-
|
|
70930
|
-
|
|
71502
|
+
visitedPairs++;
|
|
71503
|
+
if (progress && visitedPairs % reportEvery === 0) {
|
|
71504
|
+
progress.stage(DUPLICATE_STAGE_SCORING, visitedPairs, scorablePairCount, "pair");
|
|
71505
|
+
const pending = progress.yieldPoint();
|
|
71506
|
+
if (pending)
|
|
71507
|
+
await pending;
|
|
70931
71508
|
}
|
|
70932
71509
|
if (comparedPairs >= maxPairs) {
|
|
70933
71510
|
skippedCandidatePairs++;
|
|
@@ -70939,6 +71516,8 @@ async function findDuplicatesWithOpenDuplicateUnitCache(index, options = {}, pre
|
|
|
70939
71516
|
continue;
|
|
70940
71517
|
suggestions.push(suggestion);
|
|
70941
71518
|
}
|
|
71519
|
+
pairs.clear();
|
|
71520
|
+
progress?.stage(DUPLICATE_STAGE_GROUPING);
|
|
70942
71521
|
suggestions.sort(compareSuggestions2);
|
|
70943
71522
|
const includeRawPairs = options.includeRawPairs ?? false;
|
|
70944
71523
|
const groups = groupSuggestions2(suggestions, includeRawPairs).filter((group) => confidenceRank2[group.confidence] >= confidenceRank2[minConfidence]);
|
|
@@ -70947,7 +71526,7 @@ async function findDuplicatesWithOpenDuplicateUnitCache(index, options = {}, pre
|
|
|
70947
71526
|
const limitedRawSuggestions = includeRawPairs ? suggestions.slice(0, limit) : [];
|
|
70948
71527
|
const result = {
|
|
70949
71528
|
schemaVersion: 3,
|
|
70950
|
-
units:
|
|
71529
|
+
units: unitCount,
|
|
70951
71530
|
groups: limitedGroups,
|
|
70952
71531
|
omittedCounts: {
|
|
70953
71532
|
groups: omittedGroups,
|
|
@@ -70955,37 +71534,36 @@ async function findDuplicatesWithOpenDuplicateUnitCache(index, options = {}, pre
|
|
|
70955
71534
|
oversizedBuckets,
|
|
70956
71535
|
belowThresholdUnits,
|
|
70957
71536
|
overlappingPairs,
|
|
70958
|
-
candidatePairs: skippedCandidatePairs
|
|
71537
|
+
candidatePairs: omittedCandidatePairs(skippedCandidatePairs, candidatePairBudget)
|
|
70959
71538
|
},
|
|
70960
71539
|
stats: {
|
|
70961
71540
|
comparedPairs,
|
|
70962
|
-
candidatePairs:
|
|
71541
|
+
candidatePairs: candidatePairCount,
|
|
71542
|
+
...candidatePairBudget ? { candidatePairBudget } : {}
|
|
70963
71543
|
}
|
|
70964
71544
|
};
|
|
70965
71545
|
if (includeRawPairs) {
|
|
70966
71546
|
result.suggestions = limitedRawSuggestions;
|
|
70967
71547
|
}
|
|
71548
|
+
progress?.complete(unitCount);
|
|
70968
71549
|
return result;
|
|
70969
71550
|
}
|
|
70970
|
-
function
|
|
70971
|
-
let count = 0;
|
|
70972
|
-
for (const evidence of pairs.values()) {
|
|
70973
|
-
if (crossFileOnly && evidence.left.absoluteFile === evidence.right.absoluteFile)
|
|
70974
|
-
continue;
|
|
70975
|
-
if (hasLineOverlap2(evidence.left, evidence.right))
|
|
70976
|
-
continue;
|
|
70977
|
-
count += 1;
|
|
70978
|
-
}
|
|
70979
|
-
return count;
|
|
70980
|
-
}
|
|
70981
|
-
function countCandidateDuplicateGroups(pairs, crossFileOnly) {
|
|
71551
|
+
function countCandidateDuplicateGroups(pairs) {
|
|
70982
71552
|
const parents = /* @__PURE__ */ new Map();
|
|
70983
71553
|
const find = (id) => {
|
|
70984
|
-
|
|
70985
|
-
|
|
70986
|
-
|
|
70987
|
-
|
|
70988
|
-
|
|
71554
|
+
let root = id;
|
|
71555
|
+
for (; ; ) {
|
|
71556
|
+
const parent = parents.get(root);
|
|
71557
|
+
if (!parent || parent === root)
|
|
71558
|
+
break;
|
|
71559
|
+
root = parent;
|
|
71560
|
+
}
|
|
71561
|
+
let current = id;
|
|
71562
|
+
while (current !== root) {
|
|
71563
|
+
const next = parents.get(current);
|
|
71564
|
+
parents.set(current, root);
|
|
71565
|
+
current = next;
|
|
71566
|
+
}
|
|
70989
71567
|
return root;
|
|
70990
71568
|
};
|
|
70991
71569
|
const join = (left, right) => {
|
|
@@ -70996,10 +71574,6 @@ function countCandidateDuplicateGroups(pairs, crossFileOnly) {
|
|
|
70996
71574
|
parents.set(leftRoot, rightRoot);
|
|
70997
71575
|
};
|
|
70998
71576
|
for (const evidence of pairs.values()) {
|
|
70999
|
-
if (crossFileOnly && evidence.left.absoluteFile === evidence.right.absoluteFile)
|
|
71000
|
-
continue;
|
|
71001
|
-
if (hasLineOverlap2(evidence.left, evidence.right))
|
|
71002
|
-
continue;
|
|
71003
71577
|
parents.set(evidence.left.id, parents.get(evidence.left.id) ?? evidence.left.id);
|
|
71004
71578
|
parents.set(evidence.right.id, parents.get(evidence.right.id) ?? evidence.right.id);
|
|
71005
71579
|
join(evidence.left.id, evidence.right.id);
|
|
@@ -71072,7 +71646,9 @@ function duplicateContextFromResult(result, target, options) {
|
|
|
71072
71646
|
...result.omittedCounts,
|
|
71073
71647
|
groups: omittedGroups,
|
|
71074
71648
|
rawSuggestions: Math.max(0, rawSuggestions.length - limitedRawSuggestions.length),
|
|
71075
|
-
|
|
71649
|
+
// The pair limit is shared by every target of one call, so each context carries the whole call's skips,
|
|
71650
|
+
// as it carries the call's `oversizedBuckets` and `overlappingPairs`.
|
|
71651
|
+
candidatePairs: omittedCandidatePairs(result.perTargetSkippedCandidateCounts?.get(duplicateTargetKey(normalizedTarget)) ?? 0, result.stats.candidatePairBudget)
|
|
71076
71652
|
},
|
|
71077
71653
|
stats: {
|
|
71078
71654
|
...result.stats,
|
|
@@ -71160,6 +71736,7 @@ async function findDuplicatesTouchingTargets(index, targets, options, collectedU
|
|
|
71160
71736
|
const projectRoot = options.projectRoot ?? index.projectRoot;
|
|
71161
71737
|
const normalizedTargets = targets.map((target) => normalizeDuplicateTarget(target, projectRoot));
|
|
71162
71738
|
const maxBucketSize = normalizePositiveIntegerOption2(options.maxBucketSize, "maxBucketSize", DEFAULT_MAX_BUCKET_SIZE2);
|
|
71739
|
+
const maxCandidatePairs = normalizeMaxCandidatePairsOption2(options.maxCandidatePairs);
|
|
71163
71740
|
const maxPairs = options.maxPairs === void 0 ? Number.POSITIVE_INFINITY : normalizeNonNegativeIntegerOption2(options.maxPairs, "maxPairs", DEFAULT_LIMIT2);
|
|
71164
71741
|
const crossFileOnly = options.crossFileOnly ?? !(options.includeSameFile ?? false);
|
|
71165
71742
|
const minConfidence = normalizeConfidence2(options.minConfidence);
|
|
@@ -71174,18 +71751,19 @@ async function findDuplicatesTouchingTargets(index, targets, options, collectedU
|
|
|
71174
71751
|
}
|
|
71175
71752
|
const targetsTouchedByPair = (left, right) => normalizedTargets.filter((target) => unitTouchesDuplicateTarget(left, target) || unitTouchesDuplicateTarget(right, target));
|
|
71176
71753
|
const touchesAnyTarget = (left, right) => targetsTouchedByPair(left, right).length > 0;
|
|
71177
|
-
const { pairs, oversizedBuckets } =
|
|
71754
|
+
const { pairs, oversizedBuckets, skippedPairs, unscorablePairs, overlappingPairs } = await buildCandidatePairs2(preparedBuckets ?? prepareDuplicateCandidateBuckets2(units), {
|
|
71755
|
+
maxBucketSize,
|
|
71756
|
+
maxCandidatePairs,
|
|
71757
|
+
crossFileOnly,
|
|
71758
|
+
similarityHints: options.similarityHints,
|
|
71759
|
+
projectRoot,
|
|
71760
|
+
filter: { unit: touchesTarget, pair: touchesAnyTarget }
|
|
71761
|
+
});
|
|
71762
|
+
const candidatePairBudget = skippedPairs ? { limit: maxCandidatePairs, skipped: skippedPairs } : void 0;
|
|
71178
71763
|
const suggestions = [];
|
|
71179
|
-
let overlappingPairs = 0;
|
|
71180
71764
|
let comparedPairs = 0;
|
|
71181
71765
|
let skippedCandidatePairs = 0;
|
|
71182
71766
|
for (const evidence of pairs.values()) {
|
|
71183
|
-
if (crossFileOnly && evidence.left.absoluteFile === evidence.right.absoluteFile)
|
|
71184
|
-
continue;
|
|
71185
|
-
if (hasLineOverlap2(evidence.left, evidence.right)) {
|
|
71186
|
-
overlappingPairs++;
|
|
71187
|
-
continue;
|
|
71188
|
-
}
|
|
71189
71767
|
const touchedTargets = targetsTouchedByPair(evidence.left, evidence.right);
|
|
71190
71768
|
if (!touchedTargets.length)
|
|
71191
71769
|
continue;
|
|
@@ -71237,11 +71815,12 @@ async function findDuplicatesTouchingTargets(index, targets, options, collectedU
|
|
|
71237
71815
|
oversizedBuckets,
|
|
71238
71816
|
belowThresholdUnits,
|
|
71239
71817
|
overlappingPairs,
|
|
71240
|
-
candidatePairs: skippedCandidatePairs
|
|
71818
|
+
candidatePairs: omittedCandidatePairs(skippedCandidatePairs, candidatePairBudget)
|
|
71241
71819
|
},
|
|
71242
71820
|
stats: {
|
|
71243
71821
|
comparedPairs,
|
|
71244
|
-
candidatePairs: pairs.size
|
|
71822
|
+
candidatePairs: foundCandidatePairs(pairs.size, unscorablePairs, maxCandidatePairs),
|
|
71823
|
+
...candidatePairBudget ? { candidatePairBudget } : {}
|
|
71245
71824
|
},
|
|
71246
71825
|
perTargetCandidateCounts: targetCandidateCounts,
|
|
71247
71826
|
perTargetComparedCounts: targetCompareCounts,
|
|
@@ -71282,17 +71861,21 @@ async function findDuplicateContext(index, target, options = {}) {
|
|
|
71282
71861
|
const contexts = await findDuplicateContexts(index, [target], options);
|
|
71283
71862
|
return contexts[0];
|
|
71284
71863
|
}
|
|
71285
|
-
var collectDuplicateUnits2, normalizeDetectionFile2, DEFAULT_GROUP_VARIANT_LIMIT2, DEFAULT_LIMIT2, DEFAULT_MAX_BUCKET_SIZE2, DEFAULT_MAX_TOKENS2, DEFAULT_MIN_TOKENS2, DEFAULT_SHINGLE_SIZE2, DEFAULT_WINDOW_SIZE2,
|
|
71864
|
+
var collectDuplicateUnits2, normalizeDetectionFile2, buildCandidatePairs2, filterPreparedDuplicateBuckets2, prepareDuplicateCandidateBuckets2, DEFAULT_GROUP_VARIANT_LIMIT2, DEFAULT_LIMIT2, DEFAULT_MAX_BUCKET_SIZE2, DEFAULT_MAX_TOKENS2, DEFAULT_MIN_TOKENS2, DEFAULT_SHINGLE_SIZE2, DEFAULT_WINDOW_SIZE2, compareSuggestions2, confidenceRank2, groupSuggestions2, lineOverlap2, normalizeConfidence2, normalizeMaxCandidatePairsOption2, normalizeNonNegativeIntegerOption2, normalizePositiveIntegerOption2, suggestionForPair2, suggestionVariantKey2, closeDuplicateUnitCacheForIndex2, leaseDuplicateUnitCacheForIndex2, maintainDuplicateUnitDiskCache2, duplicatePreparedAnalyses;
|
|
71286
71865
|
var init_duplicates = __esm({
|
|
71287
71866
|
"dist/duplicates.js"() {
|
|
71288
71867
|
"use strict";
|
|
71289
71868
|
init_paths();
|
|
71290
71869
|
init_units();
|
|
71870
|
+
init_candidates();
|
|
71291
71871
|
init_scoring();
|
|
71292
71872
|
init_unit_cache();
|
|
71873
|
+
init_progress2();
|
|
71293
71874
|
init_unit_cache();
|
|
71875
|
+
init_scoring();
|
|
71294
71876
|
({ collectDuplicateUnits: collectDuplicateUnits2, normalizeDetectionFile: normalizeDetectionFile2 } = units_exports);
|
|
71295
|
-
({
|
|
71877
|
+
({ buildCandidatePairs: buildCandidatePairs2, filterPreparedDuplicateBuckets: filterPreparedDuplicateBuckets2, prepareDuplicateCandidateBuckets: prepareDuplicateCandidateBuckets2 } = candidates_exports);
|
|
71878
|
+
({ DEFAULT_GROUP_VARIANT_LIMIT: DEFAULT_GROUP_VARIANT_LIMIT2, DEFAULT_LIMIT: DEFAULT_LIMIT2, DEFAULT_MAX_BUCKET_SIZE: DEFAULT_MAX_BUCKET_SIZE2, DEFAULT_MAX_TOKENS: DEFAULT_MAX_TOKENS2, DEFAULT_MIN_TOKENS: DEFAULT_MIN_TOKENS2, DEFAULT_SHINGLE_SIZE: DEFAULT_SHINGLE_SIZE2, DEFAULT_WINDOW_SIZE: DEFAULT_WINDOW_SIZE2, compareSuggestions: compareSuggestions2, confidenceRank: confidenceRank2, groupSuggestions: groupSuggestions2, lineOverlap: lineOverlap2, normalizeConfidence: normalizeConfidence2, normalizeMaxCandidatePairsOption: normalizeMaxCandidatePairsOption2, normalizeNonNegativeIntegerOption: normalizeNonNegativeIntegerOption2, normalizePositiveIntegerOption: normalizePositiveIntegerOption2, suggestionForPair: suggestionForPair2, suggestionVariantKey: suggestionVariantKey2 } = scoring_exports);
|
|
71296
71879
|
({ closeDuplicateUnitCacheForIndex: closeDuplicateUnitCacheForIndex2, leaseDuplicateUnitCacheForIndex: leaseDuplicateUnitCacheForIndex2, maintainDuplicateUnitDiskCache: maintainDuplicateUnitDiskCache2 } = unit_cache_exports);
|
|
71297
71880
|
duplicatePreparedAnalyses = /* @__PURE__ */ new WeakMap();
|
|
71298
71881
|
}
|
|
@@ -73537,27 +74120,27 @@ var init_parsed_cache = __esm({
|
|
|
73537
74120
|
});
|
|
73538
74121
|
|
|
73539
74122
|
// dist/indexer/finalize.js
|
|
73540
|
-
import { performance as
|
|
74123
|
+
import { performance as performance5 } from "node:perf_hooks";
|
|
73541
74124
|
async function finalizeProjectIndex(args) {
|
|
73542
74125
|
const discoveryTimings = args.opts?.report ? args.opts.report.timings ??= {} : void 0;
|
|
73543
74126
|
let projectFiles;
|
|
73544
74127
|
if (args.projectFiles !== void 0) {
|
|
73545
74128
|
projectFiles = await args.projectFiles;
|
|
73546
74129
|
} else {
|
|
73547
|
-
const metadataDiscoveryStart =
|
|
74130
|
+
const metadataDiscoveryStart = performance5.now();
|
|
73548
74131
|
projectFiles = await discoverProjectFilesWithGitCandidates(args.projectRoot, {
|
|
73549
74132
|
...args.opts?.logLevel ? { logLevel: args.opts.logLevel } : {},
|
|
73550
74133
|
...args.knownGitCandidates !== void 0 ? { knownGitCandidates: args.knownGitCandidates } : {},
|
|
73551
74134
|
...args.discoveryContext ? { discoveryContext: args.discoveryContext } : {}
|
|
73552
74135
|
});
|
|
73553
74136
|
if (discoveryTimings) {
|
|
73554
|
-
const metadataDiscoveryMs = Math.round(
|
|
74137
|
+
const metadataDiscoveryMs = Math.round(performance5.now() - metadataDiscoveryStart);
|
|
73555
74138
|
discoveryTimings.metadataDiscoveryMs = metadataDiscoveryMs;
|
|
73556
74139
|
(discoveryTimings.steps ??= []).push({ name: "metadata-discovery", ms: metadataDiscoveryMs });
|
|
73557
74140
|
}
|
|
73558
74141
|
}
|
|
73559
74142
|
if (args.timings)
|
|
73560
|
-
args.timings.totalMs = Math.round(
|
|
74143
|
+
args.timings.totalMs = Math.round(performance5.now() - args.totalStart);
|
|
73561
74144
|
const languageExtensions = normalizeLanguageExtensions(args.opts?.languageExtensions);
|
|
73562
74145
|
const parsed = retainedParsedCache(args.parsedMap, args.opts);
|
|
73563
74146
|
return {
|
|
@@ -73594,7 +74177,7 @@ var init_finalize = __esm({
|
|
|
73594
74177
|
// dist/indexer/build-manifest.js
|
|
73595
74178
|
import fsp27 from "node:fs/promises";
|
|
73596
74179
|
import path52 from "node:path";
|
|
73597
|
-
import { performance as
|
|
74180
|
+
import { performance as performance6 } from "node:perf_hooks";
|
|
73598
74181
|
function toManifestFileEntry(entry) {
|
|
73599
74182
|
if (!entry.sig)
|
|
73600
74183
|
return void 0;
|
|
@@ -73616,22 +74199,22 @@ function serializeDeclaredContainers(projectRoot, index) {
|
|
|
73616
74199
|
function recordManifestTimingStep(timings, name, startedAt) {
|
|
73617
74200
|
if (!timings)
|
|
73618
74201
|
return;
|
|
73619
|
-
(timings.steps ??= []).push({ name, ms: Math.round(
|
|
74202
|
+
(timings.steps ??= []).push({ name, ms: Math.round(performance6.now() - startedAt) });
|
|
73620
74203
|
}
|
|
73621
74204
|
async function writeIndexManifestSnapshot(args) {
|
|
73622
74205
|
const files = args.files instanceof Map ? Object.fromEntries(args.files) : args.files;
|
|
73623
74206
|
if (!Object.keys(files).length && !args.allowEmpty)
|
|
73624
74207
|
return;
|
|
73625
|
-
const writeManifestStart =
|
|
73626
|
-
const gitHeadStartedAt =
|
|
74208
|
+
const writeManifestStart = performance6.now();
|
|
74209
|
+
const gitHeadStartedAt = performance6.now();
|
|
73627
74210
|
const lastCommit = await getGitHead(args.projectRoot);
|
|
73628
74211
|
recordManifestTimingStep(args.timings, "git-head", gitHeadStartedAt);
|
|
73629
|
-
const configHashStartedAt =
|
|
74212
|
+
const configHashStartedAt = performance6.now();
|
|
73630
74213
|
const configHashResult = args.configHash ?? await computeConfigHash(args.projectRoot, args.opts?.logLevel, args.discoveryContext);
|
|
73631
74214
|
recordManifestTimingStep(args.timings, "config-hash", configHashStartedAt);
|
|
73632
74215
|
const projectRootMtimeMs = args.symlinkDirectories !== void 0 ? (await fsp27.stat(args.projectRoot)).mtimeMs : void 0;
|
|
73633
74216
|
const configHash = recordConfigHashResult(args.manifestReport, configHashResult, args.opts?.logLevel);
|
|
73634
|
-
const transformStartedAt =
|
|
74217
|
+
const transformStartedAt = performance6.now();
|
|
73635
74218
|
const manifestData = {
|
|
73636
74219
|
version: MANIFEST_VERSION,
|
|
73637
74220
|
projectRoot: path52.resolve(args.projectRoot).replace(/\\/g, "/"),
|
|
@@ -73650,16 +74233,16 @@ async function writeIndexManifestSnapshot(args) {
|
|
|
73650
74233
|
} : {}
|
|
73651
74234
|
};
|
|
73652
74235
|
recordManifestTimingStep(args.timings, "manifest-transform", transformStartedAt);
|
|
73653
|
-
const manifestWriteStartedAt =
|
|
74236
|
+
const manifestWriteStartedAt = performance6.now();
|
|
73654
74237
|
const manifestWritten = await writeManifest2(args.projectRoot, args.opts, manifestData);
|
|
73655
74238
|
recordManifestTimingStep(args.timings, "manifest-write", manifestWriteStartedAt);
|
|
73656
74239
|
if (manifestWritten) {
|
|
73657
|
-
const cachePruneStartedAt =
|
|
74240
|
+
const cachePruneStartedAt = performance6.now();
|
|
73658
74241
|
pruneDiskModuleCache(args.projectRoot, Object.keys(files), args.opts);
|
|
73659
74242
|
recordManifestTimingStep(args.timings, "cache-prune", cachePruneStartedAt);
|
|
73660
74243
|
}
|
|
73661
74244
|
if (args.timings) {
|
|
73662
|
-
args.timings.writeManifestMs = Math.round(
|
|
74245
|
+
args.timings.writeManifestMs = Math.round(performance6.now() - writeManifestStart);
|
|
73663
74246
|
}
|
|
73664
74247
|
}
|
|
73665
74248
|
var init_build_manifest = __esm({
|
|
@@ -73736,7 +74319,7 @@ var init_native_worker_pool = __esm({
|
|
|
73736
74319
|
});
|
|
73737
74320
|
|
|
73738
74321
|
// dist/indexer/build-workers.js
|
|
73739
|
-
import { performance as
|
|
74322
|
+
import { performance as performance7 } from "node:perf_hooks";
|
|
73740
74323
|
function shouldEnableNativeWorkers(opts, fileCount) {
|
|
73741
74324
|
if (fileCount === 0)
|
|
73742
74325
|
return false;
|
|
@@ -73828,14 +74411,14 @@ async function setupWorkerPool(opts, fileCount) {
|
|
|
73828
74411
|
return {
|
|
73829
74412
|
pool,
|
|
73830
74413
|
report: report2,
|
|
73831
|
-
startTime: pool ?
|
|
74414
|
+
startTime: pool ? performance7.now() : 0,
|
|
73832
74415
|
batchSize: NATIVE_WORKER_BATCH_SIZE
|
|
73833
74416
|
};
|
|
73834
74417
|
}
|
|
73835
74418
|
async function teardownWorkerPool(setup, buildReport2) {
|
|
73836
74419
|
if (setup.pool) {
|
|
73837
74420
|
if (setup.report) {
|
|
73838
|
-
setup.report.wallClockMs = Math.round(
|
|
74421
|
+
setup.report.wallClockMs = Math.round(performance7.now() - setup.startTime);
|
|
73839
74422
|
}
|
|
73840
74423
|
try {
|
|
73841
74424
|
await setup.pool.destroy();
|
|
@@ -74275,7 +74858,7 @@ import crypto11 from "node:crypto";
|
|
|
74275
74858
|
import fs24 from "node:fs";
|
|
74276
74859
|
import fsp28 from "node:fs/promises";
|
|
74277
74860
|
import path55 from "node:path";
|
|
74278
|
-
import { performance as
|
|
74861
|
+
import { performance as performance8 } from "node:perf_hooks";
|
|
74279
74862
|
function isConfinedFileReadError(error62) {
|
|
74280
74863
|
return error62 instanceof Error && /outside project root|possible path confinement race|changed between verification and open|confined file target/u.test(error62.message);
|
|
74281
74864
|
}
|
|
@@ -74815,7 +75398,7 @@ function createIndexBuildRunState(projectRoot, opts, graphOptions = normalizeGra
|
|
|
74815
75398
|
timings: report2?.timings,
|
|
74816
75399
|
// Delegated rebuilds mint a fresh run state after the preamble; reuse the caller's
|
|
74817
75400
|
// origin so totalMs covers the whole wait, matching progress completion.
|
|
74818
|
-
totalStart: opts?.progressStartedAt ??
|
|
75401
|
+
totalStart: opts?.progressStartedAt ?? performance8.now(),
|
|
74819
75402
|
cacheMode,
|
|
74820
75403
|
cacheEnabled: cacheMode !== "off",
|
|
74821
75404
|
graphOptions
|
|
@@ -74874,9 +75457,9 @@ async function timeIndexBuildPhase(args) {
|
|
|
74874
75457
|
if (args.buildStartedAt !== void 0) {
|
|
74875
75458
|
emitIndexBuildActivity(args.opts, args.activity, args.current, args.total, args.mode ?? "build");
|
|
74876
75459
|
}
|
|
74877
|
-
const startedAt =
|
|
75460
|
+
const startedAt = performance8.now();
|
|
74878
75461
|
const result = await args.fn();
|
|
74879
|
-
recordBuildTimingStep(args.timings, { name: args.stepName, ms: Math.round(
|
|
75462
|
+
recordBuildTimingStep(args.timings, { name: args.stepName, ms: Math.round(performance8.now() - startedAt) });
|
|
74880
75463
|
return result;
|
|
74881
75464
|
}
|
|
74882
75465
|
function createCountedCheckProgress(opts, activity, total) {
|
|
@@ -74916,9 +75499,9 @@ function recordBuildTimingStep(timings, step) {
|
|
|
74916
75499
|
timings.filesystemScanMs = step.ms;
|
|
74917
75500
|
}
|
|
74918
75501
|
async function recordTimedBuildStep(timings, name, fn) {
|
|
74919
|
-
const startedAt =
|
|
75502
|
+
const startedAt = performance8.now();
|
|
74920
75503
|
const result = await fn();
|
|
74921
|
-
recordBuildTimingStep(timings, { name, ms: Math.round(
|
|
75504
|
+
recordBuildTimingStep(timings, { name, ms: Math.round(performance8.now() - startedAt) });
|
|
74922
75505
|
return result;
|
|
74923
75506
|
}
|
|
74924
75507
|
function buildConcurrency(opts) {
|
|
@@ -75212,7 +75795,7 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
|
|
|
75212
75795
|
const fileReport = initFileReport(report2);
|
|
75213
75796
|
if (fileReport)
|
|
75214
75797
|
fileReport.total = normalizedFiles.length;
|
|
75215
|
-
const manifestStart =
|
|
75798
|
+
const manifestStart = performance8.now();
|
|
75216
75799
|
const manifest = useManifest && !helperOpts?.ignoreExistingManifest ? await loadManifest(projectRoot, opts, report2) : null;
|
|
75217
75800
|
const manifestFiles = sanitizeManifestEntriesForRoot(projectRoot, manifest?.files);
|
|
75218
75801
|
const manifestOptionDiffs = manifest ? diffBuildOptions(manifest.buildOptions, opts) : [];
|
|
@@ -75228,7 +75811,7 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
|
|
|
75228
75811
|
}
|
|
75229
75812
|
}
|
|
75230
75813
|
if (timings && useManifest) {
|
|
75231
|
-
timings.manifestMs = Math.round(
|
|
75814
|
+
timings.manifestMs = Math.round(performance8.now() - manifestStart);
|
|
75232
75815
|
}
|
|
75233
75816
|
const edgeProbeConcurrency = buildConcurrency(opts);
|
|
75234
75817
|
const staleCachedEdgeFiles = /* @__PURE__ */ new Set();
|
|
@@ -75257,7 +75840,7 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
|
|
|
75257
75840
|
const moduleCacheAvailable = opts?.cache !== "disk" || diskModuleCacheExists(projectRoot, opts);
|
|
75258
75841
|
const shouldReportFileCacheCheck = Boolean(helperOpts?.reportDiscoveryProgress);
|
|
75259
75842
|
const reportFileCacheCheck = shouldReportFileCacheCheck ? createCountedCheckProgress(opts, "Checking file cache", normalizedFiles.length) : () => void 0;
|
|
75260
|
-
const cacheProbeStart =
|
|
75843
|
+
const cacheProbeStart = performance8.now();
|
|
75261
75844
|
const evictionSerialAtStart = memoryCacheEvictionSerial();
|
|
75262
75845
|
const gitAvailable = await isGitRepo(projectRoot, helperOpts?.discoveryContext?.git);
|
|
75263
75846
|
const needsPersistentSignatures = cacheEnabled || useManifest;
|
|
@@ -75327,7 +75910,7 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
|
|
|
75327
75910
|
}
|
|
75328
75911
|
}));
|
|
75329
75912
|
if (timings) {
|
|
75330
|
-
const cacheProbeMs = Math.round(
|
|
75913
|
+
const cacheProbeMs = Math.round(performance8.now() - cacheProbeStart);
|
|
75331
75914
|
timings.cacheProbeMs = cacheProbeMs;
|
|
75332
75915
|
recordBuildTimingStep(timings, { name: "cache-probe", ms: cacheProbeMs });
|
|
75333
75916
|
}
|
|
@@ -75397,7 +75980,7 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
|
|
|
75397
75980
|
const bloomFilterCache = useBloomFilters ? new (await Promise.resolve().then(() => (init_bloom_filter(), bloom_filter_exports))).BloomFilterCache() : void 0;
|
|
75398
75981
|
const persistedBloomFilters = bloomFilterCache ? await tryLoadPersistedBloomFilters(projectRoot, opts, report2) : null;
|
|
75399
75982
|
const parsedMap = /* @__PURE__ */ new Map();
|
|
75400
|
-
const parseStart =
|
|
75983
|
+
const parseStart = performance8.now();
|
|
75401
75984
|
const graph = { nodes: new Set(normalizedFiles), edges: [] };
|
|
75402
75985
|
const onFileEdges = manifestEntries ? (file2, entry) => {
|
|
75403
75986
|
const manifestEntry = toManifestFileEntry(entry);
|
|
@@ -75411,7 +75994,7 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
|
|
|
75411
75994
|
const ensureBuildProgressStarted = () => {
|
|
75412
75995
|
if (buildStartedAt !== void 0)
|
|
75413
75996
|
return;
|
|
75414
|
-
buildStartedAt =
|
|
75997
|
+
buildStartedAt = performance8.now();
|
|
75415
75998
|
emitIndexLifecycleProgress(opts, "start", "build", totalFiles);
|
|
75416
75999
|
};
|
|
75417
76000
|
if (cacheMisses.length)
|
|
@@ -75538,8 +76121,8 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
|
|
|
75538
76121
|
}
|
|
75539
76122
|
});
|
|
75540
76123
|
if (timings)
|
|
75541
|
-
timings.parseMs = Math.round(
|
|
75542
|
-
const graphStart =
|
|
76124
|
+
timings.parseMs = Math.round(performance8.now() - parseStart);
|
|
76125
|
+
const graphStart = performance8.now();
|
|
75543
76126
|
const seenGraphEdges = /* @__PURE__ */ new Set();
|
|
75544
76127
|
const appendUniqueGraphEdges = (edges) => {
|
|
75545
76128
|
if (!edges.length)
|
|
@@ -75595,7 +76178,7 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
|
|
|
75595
76178
|
});
|
|
75596
76179
|
appendUniqueGraphEdges(workspaceManifestEdges);
|
|
75597
76180
|
if (timings)
|
|
75598
|
-
timings.graphMs = Math.round(
|
|
76181
|
+
timings.graphMs = Math.round(performance8.now() - graphStart);
|
|
75599
76182
|
for (const jsonPath of jsonDependencies.values()) {
|
|
75600
76183
|
ensureJsonModule(modules, jsonPath);
|
|
75601
76184
|
}
|
|
@@ -75641,7 +76224,7 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
|
|
|
75641
76224
|
return [file2, { ...entry, ...cacheSig ? { cacheSig } : {} }];
|
|
75642
76225
|
})) : manifestEntriesForIndex;
|
|
75643
76226
|
const discoveredInsideFinalize = projectFiles === void 0;
|
|
75644
|
-
const finalizeStartedAt =
|
|
76227
|
+
const finalizeStartedAt = performance8.now();
|
|
75645
76228
|
if (buildStartedAt !== void 0) {
|
|
75646
76229
|
emitIndexBuildActivity(opts, "Finalizing project graph", totalFiles, totalFiles);
|
|
75647
76230
|
}
|
|
@@ -75661,7 +76244,7 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
|
|
|
75661
76244
|
manifestEntries: indexManifestEntries
|
|
75662
76245
|
});
|
|
75663
76246
|
if (timings) {
|
|
75664
|
-
const elapsed = Math.round(
|
|
76247
|
+
const elapsed = Math.round(performance8.now() - finalizeStartedAt);
|
|
75665
76248
|
const discoveryMs = discoveredInsideFinalize ? timings.metadataDiscoveryMs ?? 0 : 0;
|
|
75666
76249
|
const finalizeMs = discoveredInsideFinalize ? Math.max(0, elapsed - discoveryMs) : elapsed;
|
|
75667
76250
|
recordBuildTimingStep(timings, { name: "finalize", ms: finalizeMs });
|
|
@@ -75680,7 +76263,7 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
|
|
|
75680
76263
|
}
|
|
75681
76264
|
if (buildStartedAt !== void 0) {
|
|
75682
76265
|
const progressStartedAt = opts?.progressStartedAt ?? buildStartedAt;
|
|
75683
|
-
emitIndexLifecycleProgress(opts, "complete", "build", index.byFile.size,
|
|
76266
|
+
emitIndexLifecycleProgress(opts, "complete", "build", index.byFile.size, performance8.now() - progressStartedAt);
|
|
75684
76267
|
}
|
|
75685
76268
|
return index;
|
|
75686
76269
|
} finally {
|
|
@@ -75714,7 +76297,7 @@ async function buildProjectIndexWithManifestOptions(projectRoot, opts, helperOpt
|
|
|
75714
76297
|
const onDiscoveryTiming = timings ? (step) => recordBuildTimingStep(timings, step) : void 0;
|
|
75715
76298
|
if (helperOpts?.reportDiscoveryProgress)
|
|
75716
76299
|
emitIndexCheckActivity(opts, "Discovering source files");
|
|
75717
|
-
const sourceDiscoveryStart =
|
|
76300
|
+
const sourceDiscoveryStart = performance8.now();
|
|
75718
76301
|
const discoveredFiles = await listProjectFilesWithGitCandidates(projectRoot, projectPatternsForLanguageExtensions(opts), {
|
|
75719
76302
|
...opts?.discovery,
|
|
75720
76303
|
...opts?.logLevel ? { logLevel: opts.logLevel } : {},
|
|
@@ -75726,7 +76309,7 @@ async function buildProjectIndexWithManifestOptions(projectRoot, opts, helperOpt
|
|
|
75726
76309
|
...discoveryContext ? { discoveryContext } : {}
|
|
75727
76310
|
});
|
|
75728
76311
|
if (timings)
|
|
75729
|
-
timings.sourceDiscoveryMs = Math.round(
|
|
76312
|
+
timings.sourceDiscoveryMs = Math.round(performance8.now() - sourceDiscoveryStart);
|
|
75730
76313
|
const additionalFileCandidates = await normalizeIndexedFileInputsWithinRoot(projectRoot, opts?.additionalFiles ?? [], "Additional index file");
|
|
75731
76314
|
const additionalFileExistence = await probePathExistence(additionalFileCandidates, buildConcurrency(opts));
|
|
75732
76315
|
const additionalFiles = additionalFileCandidates.filter((file2) => additionalFileExistence.get(file2));
|
|
@@ -75735,7 +76318,7 @@ async function buildProjectIndexWithManifestOptions(projectRoot, opts, helperOpt
|
|
|
75735
76318
|
const transientFiles = additionalFiles.filter((file2) => !discoveredFileSet.has(file2));
|
|
75736
76319
|
if (helperOpts?.reportDiscoveryProgress)
|
|
75737
76320
|
emitIndexCheckActivity(opts, "Discovering project metadata");
|
|
75738
|
-
const metadataDiscoveryStart =
|
|
76321
|
+
const metadataDiscoveryStart = performance8.now();
|
|
75739
76322
|
const projectFiles = await discoverProjectFilesWithGitCandidates(projectRoot, {
|
|
75740
76323
|
...opts?.logLevel ? { logLevel: opts.logLevel } : {},
|
|
75741
76324
|
...discoveredSymlinkDirectories !== void 0 ? { knownSymlinkDirectories: discoveredSymlinkDirectories } : {},
|
|
@@ -75745,7 +76328,7 @@ async function buildProjectIndexWithManifestOptions(projectRoot, opts, helperOpt
|
|
|
75745
76328
|
...discoveryContext ? { discoveryContext } : {}
|
|
75746
76329
|
});
|
|
75747
76330
|
if (timings)
|
|
75748
|
-
timings.metadataDiscoveryMs = Math.round(
|
|
76331
|
+
timings.metadataDiscoveryMs = Math.round(performance8.now() - metadataDiscoveryStart);
|
|
75749
76332
|
return await buildIndexFromFileListShared(projectRoot, files, opts, {
|
|
75750
76333
|
manifestMode: useDiskCache ? "read-write" : "off",
|
|
75751
76334
|
warnNoFilesMessage: `Warning: No files found in project root: ${projectRoot}. Check codegraph.config.json globs and CLI --include-glob/--ignore-glob filters. Diagnostic: codegraph doctor`,
|
|
@@ -75765,7 +76348,7 @@ async function buildProjectIndexWithManifestOptions(projectRoot, opts, helperOpt
|
|
|
75765
76348
|
}
|
|
75766
76349
|
}
|
|
75767
76350
|
async function buildProjectIndex(projectRoot, opts) {
|
|
75768
|
-
const progressStartedAt = opts?.progressStartedAt ??
|
|
76351
|
+
const progressStartedAt = opts?.progressStartedAt ?? performance8.now();
|
|
75769
76352
|
const timings = opts?.report ? opts.report.timings ??= {} : void 0;
|
|
75770
76353
|
resetTransientBuildTimings(timings);
|
|
75771
76354
|
return buildProjectIndexWithManifestOptions(projectRoot, {
|
|
@@ -75775,7 +76358,7 @@ async function buildProjectIndex(projectRoot, opts) {
|
|
|
75775
76358
|
}
|
|
75776
76359
|
async function buildProjectIndexFromFiles(projectRoot, inputFiles, rawOpts) {
|
|
75777
76360
|
assertNativeRequiredAvailable();
|
|
75778
|
-
const opts = { ...rawOpts, progressStartedAt: rawOpts?.progressStartedAt ??
|
|
76361
|
+
const opts = { ...rawOpts, progressStartedAt: rawOpts?.progressStartedAt ?? performance8.now() };
|
|
75779
76362
|
const timings = opts.report ? opts.report.timings ??= {} : void 0;
|
|
75780
76363
|
resetTransientBuildTimings(timings);
|
|
75781
76364
|
try {
|
|
@@ -75812,7 +76395,7 @@ async function buildProjectIndexIncremental(projectRoot, rawOpts) {
|
|
|
75812
76395
|
assertNativeRequiredAvailable();
|
|
75813
76396
|
const opts = {
|
|
75814
76397
|
...rawOpts,
|
|
75815
|
-
progressStartedAt: rawOpts?.progressStartedAt ??
|
|
76398
|
+
progressStartedAt: rawOpts?.progressStartedAt ?? performance8.now()
|
|
75816
76399
|
};
|
|
75817
76400
|
const discoveryContext = opts.discoveryContext ?? createProjectDiscoveryContext(projectRoot);
|
|
75818
76401
|
const discoveryTimings = opts.report ? opts.report.timings ??= {} : void 0;
|
|
@@ -75848,7 +76431,7 @@ async function buildProjectIndexIncremental(projectRoot, rawOpts) {
|
|
|
75848
76431
|
message: "Checked project index",
|
|
75849
76432
|
current: total,
|
|
75850
76433
|
total,
|
|
75851
|
-
elapsedMs:
|
|
76434
|
+
elapsedMs: performance8.now() - totalStart
|
|
75852
76435
|
});
|
|
75853
76436
|
};
|
|
75854
76437
|
try {
|
|
@@ -75863,10 +76446,10 @@ async function buildProjectIndexIncremental(projectRoot, rawOpts) {
|
|
|
75863
76446
|
return await buildProjectIndexFromExport(projectRoot, opts, { ignoreExistingManifest: true, discoveryContext });
|
|
75864
76447
|
}
|
|
75865
76448
|
startCheckProgress();
|
|
75866
|
-
const manifestStart =
|
|
76449
|
+
const manifestStart = performance8.now();
|
|
75867
76450
|
const manifest = await recordTimedBuildStep(timings, "load-manifest", () => loadManifest(projectRoot, opts, report2));
|
|
75868
76451
|
if (timings)
|
|
75869
|
-
timings.manifestMs = Math.round(
|
|
76452
|
+
timings.manifestMs = Math.round(performance8.now() - manifestStart);
|
|
75870
76453
|
const manifestUsed = !!manifest;
|
|
75871
76454
|
const manifestReport = initManifestReport(report2, manifestUsed, false);
|
|
75872
76455
|
if (manifestReport && !manifestUsed)
|
|
@@ -75927,11 +76510,11 @@ async function buildProjectIndexIncremental(projectRoot, rawOpts) {
|
|
|
75927
76510
|
if (!discoveryTimings || opts?.filesAreProjectScope)
|
|
75928
76511
|
return await operation();
|
|
75929
76512
|
sourceDiscoveryPerformed = true;
|
|
75930
|
-
const start =
|
|
76513
|
+
const start = performance8.now();
|
|
75931
76514
|
try {
|
|
75932
76515
|
return await operation();
|
|
75933
76516
|
} finally {
|
|
75934
|
-
sourceDiscoveryMs +=
|
|
76517
|
+
sourceDiscoveryMs += performance8.now() - start;
|
|
75935
76518
|
}
|
|
75936
76519
|
};
|
|
75937
76520
|
let manifestDiffFiles = [];
|
|
@@ -76149,14 +76732,14 @@ async function buildProjectIndexIncremental(projectRoot, rawOpts) {
|
|
|
76149
76732
|
const snapshot = snapshotLoad.index;
|
|
76150
76733
|
snapshot.manifestSignaturesFresh = false;
|
|
76151
76734
|
if (snapshot.projectFiles === void 0) {
|
|
76152
|
-
const metadataDiscoveryStart =
|
|
76735
|
+
const metadataDiscoveryStart = performance8.now();
|
|
76153
76736
|
snapshot.projectFiles = await discoverProjectFilesWithGitCandidates(projectRoot, {
|
|
76154
76737
|
...opts?.logLevel ? { logLevel: opts.logLevel } : {},
|
|
76155
76738
|
...discoveredGitCandidates !== void 0 ? { knownGitCandidates: discoveredGitCandidates } : {},
|
|
76156
76739
|
...discoveryContext ? { discoveryContext } : {}
|
|
76157
76740
|
});
|
|
76158
76741
|
if (discoveryTimings)
|
|
76159
|
-
discoveryTimings.metadataDiscoveryMs = Math.round(
|
|
76742
|
+
discoveryTimings.metadataDiscoveryMs = Math.round(performance8.now() - metadataDiscoveryStart);
|
|
76160
76743
|
}
|
|
76161
76744
|
if (opts?.cache) {
|
|
76162
76745
|
snapshot.cacheMode = opts.cache;
|
|
@@ -76192,7 +76775,7 @@ async function buildProjectIndexIncremental(projectRoot, rawOpts) {
|
|
|
76192
76775
|
const snapshot = await reuseUnchangedSnapshot();
|
|
76193
76776
|
if (snapshot) {
|
|
76194
76777
|
if (timings)
|
|
76195
|
-
timings.totalMs = Math.round(
|
|
76778
|
+
timings.totalMs = Math.round(performance8.now() - totalStart);
|
|
76196
76779
|
completeCheckProgress(allFiles.size);
|
|
76197
76780
|
return snapshot;
|
|
76198
76781
|
}
|
|
@@ -76267,7 +76850,7 @@ async function buildProjectIndexIncremental(projectRoot, rawOpts) {
|
|
|
76267
76850
|
unchangedSnapshot.manifestEntries = new Map(Array.from(fileSignatures, ([file2, signature]) => [file2, toProjectIndexManifestEntry(signature)]));
|
|
76268
76851
|
unchangedSnapshot.manifestSignaturesFresh = true;
|
|
76269
76852
|
if (timings)
|
|
76270
|
-
timings.totalMs = Math.round(
|
|
76853
|
+
timings.totalMs = Math.round(performance8.now() - totalStart);
|
|
76271
76854
|
completeCheckProgress(allFiles.size);
|
|
76272
76855
|
return unchangedSnapshot;
|
|
76273
76856
|
}
|
|
@@ -76363,13 +76946,13 @@ async function buildProjectIndexIncremental(projectRoot, rawOpts) {
|
|
|
76363
76946
|
workerSetup = await setupWorkerPool(opts, countNativeWorkerEligibleFiles(changedList, opts?.languageExtensions));
|
|
76364
76947
|
let updateStartedAt;
|
|
76365
76948
|
if (changedList.length || deletedTrackedFiles.size) {
|
|
76366
|
-
updateStartedAt =
|
|
76949
|
+
updateStartedAt = performance8.now();
|
|
76367
76950
|
emitIndexLifecycleProgress(opts, "start", "update", changedList.length);
|
|
76368
76951
|
}
|
|
76369
76952
|
if (fileReport)
|
|
76370
76953
|
fileReport.changed = changedList.length;
|
|
76371
76954
|
if (changedList.length) {
|
|
76372
|
-
const parseStart =
|
|
76955
|
+
const parseStart = performance8.now();
|
|
76373
76956
|
let processedFiles = 0;
|
|
76374
76957
|
const totalFiles = changedList.length;
|
|
76375
76958
|
const fileResults = await mapLimit(changedList, conc, async (file2) => {
|
|
@@ -76431,7 +77014,7 @@ async function buildProjectIndexIncremental(projectRoot, rawOpts) {
|
|
|
76431
77014
|
writeModulesToCache(projectRoot, pendingIncrementalCacheWrites, opts);
|
|
76432
77015
|
}
|
|
76433
77016
|
if (timings)
|
|
76434
|
-
timings.parseMs = Math.round(
|
|
77017
|
+
timings.parseMs = Math.round(performance8.now() - parseStart);
|
|
76435
77018
|
}
|
|
76436
77019
|
for (const jsonPath of jsonDependencies.values()) {
|
|
76437
77020
|
ensureJsonModule(modules, jsonPath);
|
|
@@ -76465,7 +77048,7 @@ async function buildProjectIndexIncremental(projectRoot, rawOpts) {
|
|
|
76465
77048
|
}
|
|
76466
77049
|
}
|
|
76467
77050
|
const filesList = Array.from(changedFiles);
|
|
76468
|
-
const graphStart =
|
|
77051
|
+
const graphStart = performance8.now();
|
|
76469
77052
|
const graph = !filesList.length && baseGraph ? { nodes: new Set(baseGraph.nodes), edges: [...baseGraph.edges] } : await collectGraph(projectRoot, filesList, {
|
|
76470
77053
|
parsed: parsedMap,
|
|
76471
77054
|
resolveNodeModules: !!graphOptions.resolveNodeModules,
|
|
@@ -76487,7 +77070,7 @@ async function buildProjectIndexIncremental(projectRoot, rawOpts) {
|
|
|
76487
77070
|
}
|
|
76488
77071
|
});
|
|
76489
77072
|
if (timings)
|
|
76490
|
-
timings.graphMs = Math.round(
|
|
77073
|
+
timings.graphMs = Math.round(performance8.now() - graphStart);
|
|
76491
77074
|
for (const file2 of /* @__PURE__ */ new Set([...changedFiles, ...transientFiles])) {
|
|
76492
77075
|
const signature = fileSignatures.get(file2);
|
|
76493
77076
|
if (!signature || manifestEntries.has(file2))
|
|
@@ -76571,7 +77154,7 @@ async function buildProjectIndexIncremental(projectRoot, rawOpts) {
|
|
|
76571
77154
|
fn: () => writeProjectIndexSnapshot(projectRoot, opts, index, projectSnapshotFilesSignature(manifestEntries, projectRoot))
|
|
76572
77155
|
});
|
|
76573
77156
|
if (updateStartedAt !== void 0) {
|
|
76574
|
-
emitIndexLifecycleProgress(opts, "complete", "update", index.byFile.size,
|
|
77157
|
+
emitIndexLifecycleProgress(opts, "complete", "update", index.byFile.size, performance8.now() - updateStartedAt);
|
|
76575
77158
|
} else {
|
|
76576
77159
|
completeCheckProgress(allFiles.size);
|
|
76577
77160
|
}
|
|
@@ -97014,7 +97597,7 @@ async function readGitFilesAtRevision(projectRoot, revision, files) {
|
|
|
97014
97597
|
return /* @__PURE__ */ new Map();
|
|
97015
97598
|
const maxOutputBytes = Math.min(MAX_GIT_BATCH_OUTPUT_BYTES_PER_FILE * requests.length, MAX_GIT_BATCH_OUTPUT_BYTES);
|
|
97016
97599
|
try {
|
|
97017
|
-
const child = spawn2("git", ["cat-file", "--batch"], { cwd: projectRoot });
|
|
97600
|
+
const child = spawn2("git", ["cat-file", "--batch"], { windowsHide: true, cwd: projectRoot });
|
|
97018
97601
|
const stdoutChunks = [];
|
|
97019
97602
|
let stdoutBytes = 0;
|
|
97020
97603
|
let stderr = "";
|
|
@@ -97291,7 +97874,7 @@ var init_deleted = __esm({
|
|
|
97291
97874
|
});
|
|
97292
97875
|
|
|
97293
97876
|
// dist/review/candidates.js
|
|
97294
|
-
import { performance as
|
|
97877
|
+
import { performance as performance9 } from "node:perf_hooks";
|
|
97295
97878
|
function mergeCandidateTestEntries(baseCandidates, additionalCandidates) {
|
|
97296
97879
|
const merged = /* @__PURE__ */ new Map();
|
|
97297
97880
|
const upsert = (candidate) => {
|
|
@@ -97311,7 +97894,7 @@ function mergeCandidateTestEntries(baseCandidates, additionalCandidates) {
|
|
|
97311
97894
|
return Array.from(merged.values());
|
|
97312
97895
|
}
|
|
97313
97896
|
async function collectReviewCandidateTests(input2) {
|
|
97314
|
-
const candidateStart =
|
|
97897
|
+
const candidateStart = performance9.now();
|
|
97315
97898
|
const configuredMaxCandidates = input2.appliedOptions.maxCandidates;
|
|
97316
97899
|
const maxCandidates = typeof configuredMaxCandidates === "number" && Number.isFinite(configuredMaxCandidates) ? Math.max(0, Math.floor(configuredMaxCandidates)) : REVIEW_DEFAULT_CANDIDATE_TEST_LIMIT;
|
|
97317
97900
|
const candidateTests = mergeCandidateTestEntries(listCandidateTestFiles(input2.index, input2.changedFileList, input2.changedSymbolIds, {
|
|
@@ -97323,11 +97906,11 @@ async function collectReviewCandidateTests(input2) {
|
|
|
97323
97906
|
file: toProjectDisplayPath(input2.projectRoot, candidate.file)
|
|
97324
97907
|
})).sort(compareCandidateTests).slice(0, maxCandidates);
|
|
97325
97908
|
if (input2.reviewTimings) {
|
|
97326
|
-
input2.reviewTimings.candidatesMs = Math.round(
|
|
97909
|
+
input2.reviewTimings.candidatesMs = Math.round(performance9.now() - candidateStart);
|
|
97327
97910
|
}
|
|
97328
97911
|
return candidateTests;
|
|
97329
97912
|
}
|
|
97330
|
-
var
|
|
97913
|
+
var init_candidates2 = __esm({
|
|
97331
97914
|
"dist/review/candidates.js"() {
|
|
97332
97915
|
"use strict";
|
|
97333
97916
|
init_context2();
|
|
@@ -97619,7 +98202,7 @@ var init_parse4 = __esm({
|
|
|
97619
98202
|
});
|
|
97620
98203
|
|
|
97621
98204
|
// dist/review/changes.js
|
|
97622
|
-
import { performance as
|
|
98205
|
+
import { performance as performance10 } from "node:perf_hooks";
|
|
97623
98206
|
function deletedPathsForChange(change2) {
|
|
97624
98207
|
if (change2.kind === "deleted") {
|
|
97625
98208
|
return [change2.path];
|
|
@@ -97637,16 +98220,16 @@ async function collectReviewChanges(projectRoot, appliedOptions, reviewTimings)
|
|
|
97637
98220
|
const isIncludedReviewFile = createImpactIncludeMatcher(discoveryGlobRoot, appliedOptions.discovery?.includeGlobs ?? []);
|
|
97638
98221
|
const changedFiles = /* @__PURE__ */ new Set();
|
|
97639
98222
|
const explicitFiles = /* @__PURE__ */ new Set();
|
|
97640
|
-
const changesStart =
|
|
98223
|
+
const changesStart = performance10.now();
|
|
97641
98224
|
for (const file2 of appliedOptions.files ?? []) {
|
|
97642
98225
|
const normalized = normalizeFile(file2, "Review file");
|
|
97643
98226
|
changedFiles.add(normalized);
|
|
97644
98227
|
explicitFiles.add(normalized);
|
|
97645
98228
|
}
|
|
97646
98229
|
if (reviewTimings) {
|
|
97647
|
-
reviewTimings.changesMs = Math.round(
|
|
98230
|
+
reviewTimings.changesMs = Math.round(performance10.now() - changesStart);
|
|
97648
98231
|
}
|
|
97649
|
-
const diffStart =
|
|
98232
|
+
const diffStart = performance10.now();
|
|
97650
98233
|
const shouldLoadGitDiff = Boolean(appliedOptions.gitBase || appliedOptions.changedSince);
|
|
97651
98234
|
const diffText = appliedOptions.diffText ?? (shouldLoadGitDiff ? await getUnifiedDiff(projectRoot, {
|
|
97652
98235
|
base: appliedOptions.gitBase,
|
|
@@ -97655,7 +98238,7 @@ async function collectReviewChanges(projectRoot, appliedOptions, reviewTimings)
|
|
|
97655
98238
|
}) : "");
|
|
97656
98239
|
const diff = diffText ? parseUnifiedDiff(diffText) : null;
|
|
97657
98240
|
if (reviewTimings) {
|
|
97658
|
-
reviewTimings.diffMs = Math.round(
|
|
98241
|
+
reviewTimings.diffMs = Math.round(performance10.now() - diffStart);
|
|
97659
98242
|
}
|
|
97660
98243
|
const diffHunksByFile = /* @__PURE__ */ new Map();
|
|
97661
98244
|
const diffKindsByFile = /* @__PURE__ */ new Map();
|
|
@@ -99224,10 +99807,10 @@ var init_severity = __esm({
|
|
|
99224
99807
|
});
|
|
99225
99808
|
|
|
99226
99809
|
// dist/impact/budgets.js
|
|
99227
|
-
import { performance as
|
|
99810
|
+
import { performance as performance11 } from "node:perf_hooks";
|
|
99228
99811
|
function createImpactWorkBudget(options) {
|
|
99229
99812
|
return {
|
|
99230
|
-
...typeof options.timeBudgetMs === "number" && options.timeBudgetMs >= 0 ? { deadlineAt:
|
|
99813
|
+
...typeof options.timeBudgetMs === "number" && options.timeBudgetMs >= 0 ? { deadlineAt: performance11.now() + options.timeBudgetMs } : {},
|
|
99231
99814
|
...typeof options.maxReferenceLookups === "number" && options.maxReferenceLookups >= 0 ? { maxReferenceLookups: options.maxReferenceLookups } : {},
|
|
99232
99815
|
...typeof options.maxTotalReferences === "number" && options.maxTotalReferences >= 0 ? { maxTotalReferences: options.maxTotalReferences } : {},
|
|
99233
99816
|
referenceLookupsStarted: 0,
|
|
@@ -99242,7 +99825,7 @@ function isImpactDeadlineExceeded(budget) {
|
|
|
99242
99825
|
return true;
|
|
99243
99826
|
if (budget.deadlineAt === void 0)
|
|
99244
99827
|
return false;
|
|
99245
|
-
if (
|
|
99828
|
+
if (performance11.now() >= budget.deadlineAt) {
|
|
99246
99829
|
budget.deadlineExceeded = true;
|
|
99247
99830
|
return true;
|
|
99248
99831
|
}
|
|
@@ -100233,7 +100816,7 @@ var init_reference_cache = __esm({
|
|
|
100233
100816
|
// dist/review/summaries.js
|
|
100234
100817
|
import fsp39 from "node:fs/promises";
|
|
100235
100818
|
import path79 from "node:path";
|
|
100236
|
-
import { performance as
|
|
100819
|
+
import { performance as performance12 } from "node:perf_hooks";
|
|
100237
100820
|
function sortSymbols(symbols) {
|
|
100238
100821
|
return symbols.slice().sort((left, right) => symbolId(left).localeCompare(symbolId(right)));
|
|
100239
100822
|
}
|
|
@@ -100564,7 +101147,7 @@ async function summarizeChangedFiles2(input2) {
|
|
|
100564
101147
|
}
|
|
100565
101148
|
}
|
|
100566
101149
|
const defsToResolve = fileEntries.flatMap((entry) => entry.locals);
|
|
100567
|
-
const referencesStart =
|
|
101150
|
+
const referencesStart = performance12.now();
|
|
100568
101151
|
const referenceResults = includeSymbolDetails && maxCallsites > 0 ? await mapLimit(defsToResolve, referenceConcurrency, async (def) => {
|
|
100569
101152
|
const refs = await referenceCache.getUsages(index, def, {
|
|
100570
101153
|
maxReferences: maxCallsites
|
|
@@ -100572,7 +101155,7 @@ async function summarizeChangedFiles2(input2) {
|
|
|
100572
101155
|
return { def, refs };
|
|
100573
101156
|
}) : [];
|
|
100574
101157
|
if (reviewTimings) {
|
|
100575
|
-
reviewTimings.referencesMs = Math.round(
|
|
101158
|
+
reviewTimings.referencesMs = Math.round(performance12.now() - referencesStart);
|
|
100576
101159
|
}
|
|
100577
101160
|
const referencesByHandle = /* @__PURE__ */ new Map();
|
|
100578
101161
|
for (const entry of referenceResults) {
|
|
@@ -100757,7 +101340,7 @@ var init_summaries = __esm({
|
|
|
100757
101340
|
});
|
|
100758
101341
|
|
|
100759
101342
|
// dist/review.js
|
|
100760
|
-
import { performance as
|
|
101343
|
+
import { performance as performance13 } from "node:perf_hooks";
|
|
100761
101344
|
function applyReviewPresetOptions(opts) {
|
|
100762
101345
|
if (!opts.reviewDepth)
|
|
100763
101346
|
return opts;
|
|
@@ -100787,7 +101370,7 @@ async function buildReviewIndex(input2) {
|
|
|
100787
101370
|
diffChangesByFile,
|
|
100788
101371
|
...appliedOptions.graph ? { graphOptions: appliedOptions.graph } : {}
|
|
100789
101372
|
});
|
|
100790
|
-
const indexStart =
|
|
101373
|
+
const indexStart = performance13.now();
|
|
100791
101374
|
const indexReport = reviewReport?.indexReport ?? (reviewReport ? { timings: {} } : void 0);
|
|
100792
101375
|
if (reviewReport && !reviewReport.indexReport && indexReport) {
|
|
100793
101376
|
reviewReport.indexReport = indexReport;
|
|
@@ -100819,7 +101402,7 @@ async function buildReviewIndex(input2) {
|
|
|
100819
101402
|
});
|
|
100820
101403
|
}
|
|
100821
101404
|
if (reviewTimings) {
|
|
100822
|
-
reviewTimings.indexMs = Math.round(
|
|
101405
|
+
reviewTimings.indexMs = Math.round(performance13.now() - indexStart);
|
|
100823
101406
|
}
|
|
100824
101407
|
return {
|
|
100825
101408
|
index,
|
|
@@ -100837,8 +101420,8 @@ async function buildReviewReport(projectRoot, opts = {}, cached2) {
|
|
|
100837
101420
|
if (reviewReport && appliedOptions.duplicateTasks === false) {
|
|
100838
101421
|
delete reviewReport.duplicateAnalysis;
|
|
100839
101422
|
}
|
|
100840
|
-
const totalStart =
|
|
100841
|
-
const { changedFiles, explicitFiles, diffHunksByFile, diffKindsByFile, diffChangesByFile } = await collectReviewChanges(projectRoot, appliedOptions, reviewTimings);
|
|
101423
|
+
const totalStart = performance13.now();
|
|
101424
|
+
const { changedFiles, explicitFiles, diffHunksByFile, diffKindsByFile, diffChangesByFile } = cached2?.changes ?? await collectReviewChanges(projectRoot, appliedOptions, reviewTimings);
|
|
100842
101425
|
if (changedFiles.size === 0) {
|
|
100843
101426
|
const riskSummary = computeRiskSummary({
|
|
100844
101427
|
filesChanged: 0,
|
|
@@ -100871,7 +101454,7 @@ async function buildReviewReport(projectRoot, opts = {}, cached2) {
|
|
|
100871
101454
|
report3.base = appliedOptions.gitBase;
|
|
100872
101455
|
report3.head = appliedOptions.gitHead ?? "HEAD";
|
|
100873
101456
|
if (reviewTimings)
|
|
100874
|
-
reviewTimings.totalMs = Math.round(
|
|
101457
|
+
reviewTimings.totalMs = Math.round(performance13.now() - totalStart);
|
|
100875
101458
|
return report3;
|
|
100876
101459
|
}
|
|
100877
101460
|
const changedFileList = Array.from(changedFiles).sort((left, right) => left.localeCompare(right));
|
|
@@ -100950,7 +101533,7 @@ async function buildReviewReport(projectRoot, opts = {}, cached2) {
|
|
|
100950
101533
|
riskRelevantParseFailures,
|
|
100951
101534
|
exportedChangedCount
|
|
100952
101535
|
});
|
|
100953
|
-
const duplicateAnalysisStart =
|
|
101536
|
+
const duplicateAnalysisStart = performance13.now();
|
|
100954
101537
|
if (appliedOptions.duplicateTasks !== false) {
|
|
100955
101538
|
const duplicateReview = await collectReviewDuplicateTasks({
|
|
100956
101539
|
projectRoot,
|
|
@@ -100971,10 +101554,10 @@ async function buildReviewReport(projectRoot, opts = {}, cached2) {
|
|
|
100971
101554
|
}
|
|
100972
101555
|
}
|
|
100973
101556
|
if (reviewTimings && appliedOptions.duplicateTasks !== false) {
|
|
100974
|
-
reviewTimings.duplicateAnalysisMs = Math.round(
|
|
101557
|
+
reviewTimings.duplicateAnalysisMs = Math.round(performance13.now() - duplicateAnalysisStart);
|
|
100975
101558
|
}
|
|
100976
101559
|
if (reviewTimings)
|
|
100977
|
-
reviewTimings.totalMs = Math.round(
|
|
101560
|
+
reviewTimings.totalMs = Math.round(performance13.now() - totalStart);
|
|
100978
101561
|
return report2;
|
|
100979
101562
|
}
|
|
100980
101563
|
function buildSymbolDefLookup(index) {
|
|
@@ -101135,7 +101718,7 @@ var init_review2 = __esm({
|
|
|
101135
101718
|
init_workspace();
|
|
101136
101719
|
init_project_files();
|
|
101137
101720
|
init_concurrency();
|
|
101138
|
-
|
|
101721
|
+
init_candidates2();
|
|
101139
101722
|
init_changes();
|
|
101140
101723
|
init_deleted();
|
|
101141
101724
|
init_report();
|
|
@@ -102361,7 +102944,7 @@ async function explainCodegraphTargetWithSession(session, request) {
|
|
|
102361
102944
|
const snapshot = await session.loadProject();
|
|
102362
102945
|
const lookup2 = buildSymbolLookup(snapshot);
|
|
102363
102946
|
const resolved = resolveTarget(snapshot, lookup2, request.target);
|
|
102364
|
-
return await buildExplanation(snapshot, lookup2, resolved, request);
|
|
102947
|
+
return await buildExplanation(snapshot, lookup2, resolved, request, session);
|
|
102365
102948
|
}
|
|
102366
102949
|
async function resolveCodegraphTargetWithSession(session, request) {
|
|
102367
102950
|
const snapshot = await session.loadProject();
|
|
@@ -102525,7 +103108,7 @@ function basename2(name) {
|
|
|
102525
103108
|
const parts = name.split(".");
|
|
102526
103109
|
return parts[parts.length - 1] ?? name;
|
|
102527
103110
|
}
|
|
102528
|
-
async function buildExplanation(snapshot, lookup2, resolved, request) {
|
|
103111
|
+
async function buildExplanation(snapshot, lookup2, resolved, request, session) {
|
|
102529
103112
|
const maxDependencies = defaultAgentLimit(request.maxDependencies, AGENT_EXPLAIN_DEFAULT_DEPENDENCY_LIMIT, AGENT_EXPLAIN_MAX_DEPENDENCY_LIMIT);
|
|
102530
103113
|
const maxReferences = defaultAgentLimit(request.maxReferences ?? request.maxDependencies, AGENT_EXPLAIN_DEFAULT_DEPENDENCY_LIMIT, AGENT_EXPLAIN_MAX_DEPENDENCY_LIMIT);
|
|
102531
103114
|
const maxRelatedSqlObjects = defaultAgentLimit(request.maxRelatedSqlObjects ?? request.maxDependencies, AGENT_EXPLAIN_DEFAULT_DEPENDENCY_LIMIT, AGENT_EXPLAIN_MAX_DEPENDENCY_LIMIT);
|
|
@@ -102549,7 +103132,7 @@ async function buildExplanation(snapshot, lookup2, resolved, request) {
|
|
|
102549
103132
|
const references = referenceContext.references;
|
|
102550
103133
|
const snippets = referenceContext.snippets;
|
|
102551
103134
|
const relatedSqlObjects = await collectRelatedSqlObjects(snapshot, lookup2, resolved, file2, maxRelatedSqlObjects);
|
|
102552
|
-
const duplicates = await collectDuplicateContext(snapshot, resolved, relFile, maxDuplicates);
|
|
103135
|
+
const duplicates = await collectDuplicateContext(snapshot, session, resolved, relFile, maxDuplicates);
|
|
102553
103136
|
const followUps = collectFollowUps(snapshot, resolved, boundedSymbols.items, relFile, duplicates.items);
|
|
102554
103137
|
const changedContext = await collectChangedContext(request);
|
|
102555
103138
|
return {
|
|
@@ -102692,7 +103275,7 @@ function compareDependencies(left, right) {
|
|
|
102692
103275
|
return depthDelta;
|
|
102693
103276
|
return left.file.localeCompare(right.file);
|
|
102694
103277
|
}
|
|
102695
|
-
async function collectDuplicateContext(snapshot, resolved, relFile, limit) {
|
|
103278
|
+
async function collectDuplicateContext(snapshot, session, resolved, relFile, limit) {
|
|
102696
103279
|
if (resolved.kind === "sql_object")
|
|
102697
103280
|
return emptyAgentBoundedList();
|
|
102698
103281
|
const target = resolved.kind === "file" ? { file: relFile } : {
|
|
@@ -102700,13 +103283,15 @@ async function collectDuplicateContext(snapshot, resolved, relFile, limit) {
|
|
|
102700
103283
|
startLine: resolved.def.range.start.line,
|
|
102701
103284
|
endLine: resolved.def.range.end.line
|
|
102702
103285
|
};
|
|
102703
|
-
const
|
|
103286
|
+
const options = {
|
|
102704
103287
|
projectRoot: snapshot.root,
|
|
102705
103288
|
minConfidence: "medium",
|
|
102706
103289
|
includeSameFile: true,
|
|
102707
103290
|
limit,
|
|
102708
103291
|
maxPairs: AGENT_DUPLICATE_MAX_PAIRS
|
|
102709
|
-
}
|
|
103292
|
+
};
|
|
103293
|
+
const analysis = await session.loadDuplicateAnalysis?.();
|
|
103294
|
+
const result = analysis ? (await findDuplicateContextsWithPreparedAnalysis(analysis, [target], options))[0] : await findDuplicateContext(snapshot.index, target, options);
|
|
102710
103295
|
return {
|
|
102711
103296
|
items: result.groups.map((group) => summarizeDuplicateGroup(group, result.target)),
|
|
102712
103297
|
omitted: result.omittedCounts.groups + result.omittedCounts.candidatePairs
|
|
@@ -104071,7 +104656,7 @@ function findQueryIndexChunkCandidates(store, rankTerms, normalizedRankPhrase =
|
|
|
104071
104656
|
};
|
|
104072
104657
|
}
|
|
104073
104658
|
var QUERY_INDEX_CANDIDATE_VERSION;
|
|
104074
|
-
var
|
|
104659
|
+
var init_candidates3 = __esm({
|
|
104075
104660
|
"dist/agent/query-index/candidates.js"() {
|
|
104076
104661
|
"use strict";
|
|
104077
104662
|
init_content();
|
|
@@ -104648,9 +105233,8 @@ async function searchCodegraphWithSession(session, request) {
|
|
|
104648
105233
|
return freshResponse;
|
|
104649
105234
|
return { ...freshResponse, query: request.query };
|
|
104650
105235
|
}
|
|
104651
|
-
const mode = request.mode ?? "hybrid";
|
|
104652
105236
|
let queryIndex;
|
|
104653
|
-
if (
|
|
105237
|
+
if (searchUsesQueryIndex(request)) {
|
|
104654
105238
|
const { ensureSessionQueryIndex: ensureSessionQueryIndex2 } = await Promise.resolve().then(() => (init_session_store(), session_store_exports));
|
|
104655
105239
|
queryIndex = await ensureSessionQueryIndex2(session, snapshot);
|
|
104656
105240
|
}
|
|
@@ -104847,6 +105431,10 @@ function searchNeedsSymbolGraph(request) {
|
|
|
104847
105431
|
const mode = request.mode ?? "hybrid";
|
|
104848
105432
|
return mode !== "path" && mode !== "text" && mode !== "sql";
|
|
104849
105433
|
}
|
|
105434
|
+
function searchUsesQueryIndex(request) {
|
|
105435
|
+
const mode = request.mode ?? "hybrid";
|
|
105436
|
+
return mode === "hybrid" || mode === "text";
|
|
105437
|
+
}
|
|
104850
105438
|
function buildQueryTerms(input2, snapshot) {
|
|
104851
105439
|
const normalized = normalizeSearchText(input2);
|
|
104852
105440
|
const tokenSequence = normalized.split(/\s+/).filter((token) => token.length);
|
|
@@ -105613,7 +106201,7 @@ var init_search = __esm({
|
|
|
105613
106201
|
init_session();
|
|
105614
106202
|
init_follow_ups();
|
|
105615
106203
|
init_content();
|
|
105616
|
-
|
|
106204
|
+
init_candidates3();
|
|
105617
106205
|
init_store();
|
|
105618
106206
|
init_session_lifecycle();
|
|
105619
106207
|
DEFAULT_LIMIT3 = 20;
|
|
@@ -106715,33 +107303,34 @@ ${SHARED_INDEX_OPTIONS_HELP}
|
|
|
106715
107303
|
SERVER_HELP_TEXT = `codegraph server - Manage a shared project-local MCP HTTP server
|
|
106716
107304
|
|
|
106717
107305
|
Usage:
|
|
106718
|
-
codegraph server start [--root <path>] [--host <host>] [--port <1-65535>] [--startup-timeout-ms <1-86400000>] [--json] [--replace] [--warmup | --warmup-symbols | --no-warmup] [--no-watch]
|
|
107306
|
+
codegraph server start [--root <path>] [--host <host>] [--port <1-65535>] [--startup-timeout-ms <1-86400000>] [--index-wait-ms <ms>] [--json] [--replace] [--warmup | --warmup-symbols | --no-warmup] [--no-watch]
|
|
106719
107307
|
codegraph server status [--root <path>] [--json | --pretty]
|
|
106720
107308
|
codegraph server stop [--root <path>]
|
|
106721
107309
|
|
|
106722
107310
|
Behavior:
|
|
106723
107311
|
start runs codegraph mcp serve in a separate process, waits for a challenged /health proof, then writes .codegraph/server.json. --json emits the started registry with status and update fields; startup diagnostics go to .codegraph/server.log.
|
|
106724
|
-
The default server listens on 127.0.0.1:7331. A public bind requires an explicit --host. --startup-timeout-ms defaults to 15000 and
|
|
107312
|
+
The default server listens on 127.0.0.1:7331. A public bind requires an explicit --host. --startup-timeout-ms defaults to 15000 and covers starting the process; the warmup builds in the background and does not count against it. By default the server warms the base session cache and the search index; --no-warmup starts lazily instead, and --warmup-symbols also warms the detailed symbol graph.
|
|
106725
107313
|
status retries proven health checks and reports a verification remedy for an unreachable or mismatched server. stop removes only confirmed stale registries or signals a Codegraph server whose root, process, and startup time match the registry.
|
|
106726
107314
|
|
|
106727
107315
|
Forwarded startup options:
|
|
106728
107316
|
--cache, --cache-dir, --cache-strict, --cache-verify, --threads, --workers,
|
|
106729
|
-
--include-glob, --ignore-glob, --no-gitignore, --no-watch, and --resolution-hint pass to mcp serve.
|
|
107317
|
+
--include-glob, --ignore-glob, --no-gitignore, --no-watch, --index-wait-ms, and --resolution-hint pass to mcp serve.
|
|
106730
107318
|
|
|
106731
107319
|
Safety:
|
|
106732
107320
|
The registry stores process metadata and a non-secret credential ID. Its credential remains in the per-user Codegraph state directory, outside the project and separate from compiler cache data. An installed-version change requires an explicit server restart; Codegraph does not replace mapped native files or terminate clients automatically.
|
|
106733
107321
|
`;
|
|
106734
107322
|
MCP_HELP_TEXT = `codegraph mcp - Serve MCP tools for agent graph navigation
|
|
106735
107323
|
|
|
106736
|
-
Usage: codegraph mcp [serve] [--root <path>] [--artifact <path>] [--stdio | --port <number>] [--host <host>] [--idle-timeout-ms <ms>] [--allow-build] [--warmup | --warmup-symbols | --no-warmup] [--no-watch]
|
|
107324
|
+
Usage: codegraph mcp [serve] [--root <path>] [--artifact <path>] [--stdio | --port <number>] [--host <host>] [--idle-timeout-ms <ms>] [--index-wait-ms <ms>] [--allow-build] [--warmup | --warmup-symbols | --no-warmup] [--no-watch]
|
|
106737
107325
|
|
|
106738
107326
|
Transports:
|
|
106739
107327
|
--stdio Serve MCP over stdio (default)
|
|
106740
107328
|
--port <number> Serve Streamable HTTP at /mcp
|
|
106741
|
-
--warmup Build the base session cache
|
|
106742
|
-
--warmup-symbols
|
|
106743
|
-
--no-warmup Skip startup warmup; the first tool call
|
|
107329
|
+
--warmup Build the base session cache and the search index in the background after startup (default)
|
|
107330
|
+
--warmup-symbols Also build the detailed symbol graph in the background
|
|
107331
|
+
--no-warmup Skip the startup warmup; the first tool call that needs the index starts the build
|
|
106744
107332
|
--no-watch Do not watch project files; rely on the freshness check of each tool call
|
|
107333
|
+
--index-wait-ms <ms> Longest wait of search, explore, orient, get_file with includeGraphContext, review, packet_get, workspace_symbols, and impact for a running index build before they answer index_building (default 15000; 0 waits without limit)
|
|
106745
107334
|
|
|
106746
107335
|
Index Options:
|
|
106747
107336
|
--cache <mode> Session cache mode: disk, memory, off
|
|
@@ -106759,7 +107348,7 @@ Tools are read-only unless --allow-build is passed.
|
|
|
106759
107348
|
`;
|
|
106760
107349
|
MCP_SERVE_HELP_TEXT = `codegraph mcp serve - MCP server for agent graph navigation
|
|
106761
107350
|
|
|
106762
|
-
Usage: codegraph mcp [serve] [--root <path>] [--artifact <path>] [--stdio | --port <number>] [--host <host>] [--idle-timeout-ms <ms>] [--allow-build] [--warmup | --warmup-symbols | --no-warmup] [--no-watch]
|
|
107351
|
+
Usage: codegraph mcp [serve] [--root <path>] [--artifact <path>] [--stdio | --port <number>] [--host <host>] [--idle-timeout-ms <ms>] [--index-wait-ms <ms>] [--allow-build] [--warmup | --warmup-symbols | --no-warmup] [--no-watch]
|
|
106763
107352
|
|
|
106764
107353
|
Tools:
|
|
106765
107354
|
orient Build a compact first-turn repo packet
|
|
@@ -106793,7 +107382,8 @@ Index Options:
|
|
|
106793
107382
|
Defaults:
|
|
106794
107383
|
Transport defaults to stdio.
|
|
106795
107384
|
HTTP transport binds to 127.0.0.1 unless --host is passed and serves /mcp.
|
|
106796
|
-
|
|
107385
|
+
The server answers initialize and tools/list at once. By default it then builds the base session cache and the search index in the background; --warmup-symbols also warms the detailed symbol graph, and --no-warmup builds only when a tool call needs the index.
|
|
107386
|
+
search, explore, orient, get_file with includeGraphContext, review, packet_get, workspace_symbols, and impact wait for a running build for at most --index-wait-ms (default 15000, well below the 30 seconds that clients commonly allow). Past that they answer { "status": "index_building" } with progress and a retry hint; the build continues, and the same call succeeds once it ends. Every other tool waits for the index without a limit.
|
|
106797
107387
|
Warmup uses the configured session cache and shared index flags.
|
|
106798
107388
|
The server watches project files and refreshes the index in the background: 500 ms after the last change, at most once every 5 seconds, and paused after 30 minutes without a tool call. --no-watch relies on the freshness check of each tool call instead.
|
|
106799
107389
|
Tools are read-only unless --allow-build is passed.
|
|
@@ -106831,11 +107421,15 @@ Options:
|
|
|
106831
107421
|
--min-tokens Minimum unit tokens. Defaults to 40, or 80 under cleanup profile.
|
|
106832
107422
|
--max-tokens Maximum fallback chunk tokens. Defaults to 800.
|
|
106833
107423
|
--max-bucket-size Skip candidate buckets larger than this value. Defaults to 200.
|
|
107424
|
+
--max-candidate-pairs
|
|
107425
|
+
Keep at most this many candidate pairs for scoring, strongest evidence first. Defaults to 2000000; maximum 16000000.
|
|
106834
107426
|
|
|
106835
107427
|
Output:
|
|
106836
107428
|
Pretty output is the default and emits one line per group with file spans, symbol or chunk labels, confidence, clone type, score, reduced lines, estimated reducible lines, token counts, heuristic family annotations, and cleanup labels.
|
|
106837
107429
|
Pretty output also emits a compact summary footer unless --no-summary is passed.
|
|
106838
107430
|
JSON output reports grouped duplicate findings, confidence, clone type, metrics, reduced-line fields, cleanup labels, clustered locations, omission counts including skipped candidate pairs, and pair stats.
|
|
107431
|
+
When --max-candidate-pairs drops pairs, stats.candidatePairBudget names the limit and the skipped count, and pretty output says the results are partial.
|
|
107432
|
+
Progress for unit collection, candidate pairs, scoring, and grouping, and the total elapsed time, goes to stderr; use --progress or --no-progress.
|
|
106839
107433
|
Grouped duplicate JSON uses schemaVersion 3.
|
|
106840
107434
|
--raw-pairs is only supported with similarity-ranked JSON output and cannot be combined with the cleanup profile.
|
|
106841
107435
|
`;
|
|
@@ -107121,7 +107715,7 @@ var search_exports = {};
|
|
|
107121
107715
|
__export(search_exports, {
|
|
107122
107716
|
handleSearchCommand: () => handleSearchCommand
|
|
107123
107717
|
});
|
|
107124
|
-
import { performance as
|
|
107718
|
+
import { performance as performance14 } from "node:perf_hooks";
|
|
107125
107719
|
function parseAgentSearchMode(rawValue) {
|
|
107126
107720
|
if (rawValue === void 0)
|
|
107127
107721
|
return "hybrid";
|
|
@@ -107131,7 +107725,7 @@ function parseAgentSearchMode(rawValue) {
|
|
|
107131
107725
|
throw new Error(`Invalid --mode value "${rawValue}". Expected hybrid, symbol, path, text, graph, or sql.`);
|
|
107132
107726
|
}
|
|
107133
107727
|
async function handleSearchCommand(context) {
|
|
107134
|
-
const commandStart =
|
|
107728
|
+
const commandStart = performance14.now();
|
|
107135
107729
|
const query = context.positionals.join(" ").trim();
|
|
107136
107730
|
if (!query) {
|
|
107137
107731
|
context.writeStderrLine(SEARCH_HELP_TEXT.trimEnd());
|
|
@@ -107155,7 +107749,7 @@ async function handleSearchCommand(context) {
|
|
|
107155
107749
|
context.writeStdoutLine(formatAgentSearchResponse(response));
|
|
107156
107750
|
}
|
|
107157
107751
|
if (context.commandReport && context.writeCommandReport) {
|
|
107158
|
-
context.commandReport.timings.commandMs = Math.round(
|
|
107752
|
+
context.commandReport.timings.commandMs = Math.round(performance14.now() - commandStart);
|
|
107159
107753
|
context.commandReport.timings.totalMs = context.commandReport.timings.commandMs;
|
|
107160
107754
|
await context.writeCommandReport(context.commandReport, context.reportFile);
|
|
107161
107755
|
}
|
|
@@ -107632,25 +108226,25 @@ function getCallHierarchyIndex(graph) {
|
|
|
107632
108226
|
for (const edge of graph.edges) {
|
|
107633
108227
|
if (edge.label !== "calls")
|
|
107634
108228
|
continue;
|
|
107635
|
-
const
|
|
107636
|
-
const relationship = relationshipByPair.get(
|
|
108229
|
+
const pairKey = `${edge.from}->${edge.to}`;
|
|
108230
|
+
const relationship = relationshipByPair.get(pairKey) ?? {
|
|
107637
108231
|
caller: edge.from,
|
|
107638
108232
|
callee: edge.to,
|
|
107639
108233
|
sites: [],
|
|
107640
108234
|
unresolvedSites: 0
|
|
107641
108235
|
};
|
|
107642
108236
|
if (edge.site) {
|
|
107643
|
-
const siteKeys = siteKeysByPair.get(
|
|
108237
|
+
const siteKeys = siteKeysByPair.get(pairKey) ?? /* @__PURE__ */ new Set();
|
|
107644
108238
|
const siteKey3 = callsiteKey(edge.site);
|
|
107645
108239
|
if (!siteKeys.has(siteKey3)) {
|
|
107646
108240
|
siteKeys.add(siteKey3);
|
|
107647
108241
|
relationship.sites.push(edge.site);
|
|
107648
108242
|
}
|
|
107649
|
-
siteKeysByPair.set(
|
|
108243
|
+
siteKeysByPair.set(pairKey, siteKeys);
|
|
107650
108244
|
} else {
|
|
107651
108245
|
relationship.unresolvedSites += 1;
|
|
107652
108246
|
}
|
|
107653
|
-
relationshipByPair.set(
|
|
108247
|
+
relationshipByPair.set(pairKey, relationship);
|
|
107654
108248
|
}
|
|
107655
108249
|
for (const relationship of relationshipByPair.values()) {
|
|
107656
108250
|
relationship.sites.sort(compareCallsites);
|
|
@@ -108904,7 +109498,7 @@ var init_base = __esm({
|
|
|
108904
109498
|
const cwd = opts.cwd || process.cwd();
|
|
108905
109499
|
const args = gitDiffArgs(opts.base, opts.head, ["--no-ext-diff", "--unified=0"]);
|
|
108906
109500
|
try {
|
|
108907
|
-
const child = spawn3("git", args, { cwd });
|
|
109501
|
+
const child = spawn3("git", args, { windowsHide: true, cwd });
|
|
108908
109502
|
let stderr = "";
|
|
108909
109503
|
child.stderr.on("data", (data) => {
|
|
108910
109504
|
stderr += String(data);
|
|
@@ -113809,7 +114403,7 @@ __export(orient_exports, {
|
|
|
113809
114403
|
formatAgentOrientation: () => formatAgentOrientation,
|
|
113810
114404
|
handleOrientCommand: () => handleOrientCommand
|
|
113811
114405
|
});
|
|
113812
|
-
import { performance as
|
|
114406
|
+
import { performance as performance15 } from "node:perf_hooks";
|
|
113813
114407
|
function parseAgentOrientBudget(rawValue) {
|
|
113814
114408
|
if (rawValue === void 0)
|
|
113815
114409
|
return "small";
|
|
@@ -113827,7 +114421,7 @@ function parseAgentOrientHealthMode(rawValue) {
|
|
|
113827
114421
|
throw new Error(`Invalid --health value "${rawValue}". Expected skip, summary, or full.`);
|
|
113828
114422
|
}
|
|
113829
114423
|
async function handleOrientCommand(context) {
|
|
113830
|
-
const commandStart =
|
|
114424
|
+
const commandStart = performance15.now();
|
|
113831
114425
|
const healthMode = parseAgentOrientHealthMode(context.getOpt("--health"));
|
|
113832
114426
|
const writesJson = context.hasFlag("--json");
|
|
113833
114427
|
const indexReport = context.commandReport?.index;
|
|
@@ -113849,7 +114443,7 @@ async function handleOrientCommand(context) {
|
|
|
113849
114443
|
context.writeStdoutLine(formatAgentOrientation(response));
|
|
113850
114444
|
}
|
|
113851
114445
|
if (context.commandReport && context.writeCommandReport) {
|
|
113852
|
-
context.commandReport.timings.commandMs = Math.round(
|
|
114446
|
+
context.commandReport.timings.commandMs = Math.round(performance15.now() - commandStart);
|
|
113853
114447
|
context.commandReport.timings.totalMs = context.commandReport.timings.commandMs;
|
|
113854
114448
|
await context.writeCommandReport(context.commandReport, context.reportFile);
|
|
113855
114449
|
}
|
|
@@ -131149,17 +131743,286 @@ var init_project_watcher = __esm({
|
|
|
131149
131743
|
}
|
|
131150
131744
|
});
|
|
131151
131745
|
|
|
131746
|
+
// dist/mcp/cancellation.js
|
|
131747
|
+
function mcpCancellationError(signal) {
|
|
131748
|
+
const reason = signal.reason;
|
|
131749
|
+
if (reason instanceof Error && reason.name !== "AbortError")
|
|
131750
|
+
return reason;
|
|
131751
|
+
return new Error("MCP tool call was cancelled.");
|
|
131752
|
+
}
|
|
131753
|
+
var init_cancellation = __esm({
|
|
131754
|
+
"dist/mcp/cancellation.js"() {
|
|
131755
|
+
"use strict";
|
|
131756
|
+
}
|
|
131757
|
+
});
|
|
131758
|
+
|
|
131759
|
+
// dist/mcp/stale-install.js
|
|
131760
|
+
function isStaleInstallError(error62) {
|
|
131761
|
+
let current = error62;
|
|
131762
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH && current instanceof Error; depth += 1) {
|
|
131763
|
+
if ("code" in current && (current.code === "ERR_MODULE_NOT_FOUND" || current.code === "MODULE_NOT_FOUND"))
|
|
131764
|
+
return true;
|
|
131765
|
+
if (MODULE_NOT_FOUND_MESSAGE.test(current.message))
|
|
131766
|
+
return true;
|
|
131767
|
+
current = current.cause;
|
|
131768
|
+
}
|
|
131769
|
+
return false;
|
|
131770
|
+
}
|
|
131771
|
+
function describeMcpRuntimeError(error62) {
|
|
131772
|
+
return isStaleInstallError(error62) ? STALE_INSTALL_MESSAGE : errorMessage(error62);
|
|
131773
|
+
}
|
|
131774
|
+
var STALE_INSTALL_MESSAGE, MODULE_NOT_FOUND_MESSAGE, MAX_CAUSE_DEPTH;
|
|
131775
|
+
var init_stale_install = __esm({
|
|
131776
|
+
"dist/mcp/stale-install.js"() {
|
|
131777
|
+
"use strict";
|
|
131778
|
+
init_errors();
|
|
131779
|
+
STALE_INSTALL_MESSAGE = "The codegraph package changed on disk after this MCP server started, so a part of it that had not been loaded yet is gone. Restart the MCP server (or reload the MCP client) to run the installed version.";
|
|
131780
|
+
MODULE_NOT_FOUND_MESSAGE = /^Cannot find (?:module|package)\b/;
|
|
131781
|
+
MAX_CAUSE_DEPTH = 5;
|
|
131782
|
+
}
|
|
131783
|
+
});
|
|
131784
|
+
|
|
131785
|
+
// dist/mcp/index-readiness.js
|
|
131786
|
+
function assertMcpIndexWait(value) {
|
|
131787
|
+
if (!Number.isSafeInteger(value) || value < 0 || value > MAX_MCP_INDEX_WAIT_MS) {
|
|
131788
|
+
throw new RangeError(`mcpIndexWaitMs must be a whole number from 0 through ${MAX_MCP_INDEX_WAIT_MS}; 0 disables the budget.`);
|
|
131789
|
+
}
|
|
131790
|
+
return value;
|
|
131791
|
+
}
|
|
131792
|
+
function searchNeeds(request) {
|
|
131793
|
+
if (canUsePathFastPath(request))
|
|
131794
|
+
return [];
|
|
131795
|
+
const needs = [searchNeedsSymbolGraph(request) ? "symbolGraph" : "index"];
|
|
131796
|
+
if (searchUsesQueryIndex(request))
|
|
131797
|
+
needs.push("queryIndex");
|
|
131798
|
+
return needs;
|
|
131799
|
+
}
|
|
131800
|
+
function exploreNeeds(request) {
|
|
131801
|
+
const needs = searchNeeds({});
|
|
131802
|
+
if (request.includeSource && request.maxPackets !== 0)
|
|
131803
|
+
needs.push("detailedGraph", "duplicates");
|
|
131804
|
+
return needs;
|
|
131805
|
+
}
|
|
131806
|
+
function describeBuildUpdate(update) {
|
|
131807
|
+
if (update.activity)
|
|
131808
|
+
return update.activity;
|
|
131809
|
+
if (update.phase === "start")
|
|
131810
|
+
return update.message;
|
|
131811
|
+
if (update.mode === "update")
|
|
131812
|
+
return "Updating project index";
|
|
131813
|
+
if (update.mode === "check")
|
|
131814
|
+
return "Checking project index";
|
|
131815
|
+
return "Indexing files";
|
|
131816
|
+
}
|
|
131817
|
+
function createMcpBuildProgress() {
|
|
131818
|
+
let latest;
|
|
131819
|
+
return {
|
|
131820
|
+
record: (update) => {
|
|
131821
|
+
if (update.phase === "complete") {
|
|
131822
|
+
latest = void 0;
|
|
131823
|
+
return;
|
|
131824
|
+
}
|
|
131825
|
+
latest = { activity: describeBuildUpdate(update), current: update.current, total: update.total };
|
|
131826
|
+
},
|
|
131827
|
+
latest: () => latest
|
|
131828
|
+
};
|
|
131829
|
+
}
|
|
131830
|
+
function settleWithinBudget(work, budgetMs, signal) {
|
|
131831
|
+
if (signal?.aborted)
|
|
131832
|
+
return Promise.reject(mcpCancellationError(signal));
|
|
131833
|
+
const { promise: promise3, resolve: resolve3, reject } = Promise.withResolvers();
|
|
131834
|
+
let timer;
|
|
131835
|
+
const onAbort = () => {
|
|
131836
|
+
cleanup();
|
|
131837
|
+
if (signal)
|
|
131838
|
+
reject(mcpCancellationError(signal));
|
|
131839
|
+
};
|
|
131840
|
+
const cleanup = () => {
|
|
131841
|
+
clearTimeout(timer);
|
|
131842
|
+
signal?.removeEventListener("abort", onAbort);
|
|
131843
|
+
};
|
|
131844
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
131845
|
+
if (budgetMs > 0) {
|
|
131846
|
+
timer = setTimeout(() => {
|
|
131847
|
+
cleanup();
|
|
131848
|
+
resolve3("timeout");
|
|
131849
|
+
}, budgetMs);
|
|
131850
|
+
timer.unref();
|
|
131851
|
+
}
|
|
131852
|
+
work.then(() => {
|
|
131853
|
+
cleanup();
|
|
131854
|
+
resolve3("ready");
|
|
131855
|
+
}, (error62) => {
|
|
131856
|
+
cleanup();
|
|
131857
|
+
reject(error62 instanceof Error ? error62 : new Error(String(error62)));
|
|
131858
|
+
});
|
|
131859
|
+
return promise3;
|
|
131860
|
+
}
|
|
131861
|
+
function createMcpIndexReadiness(session, options) {
|
|
131862
|
+
const pending = /* @__PURE__ */ new Set();
|
|
131863
|
+
let busySince;
|
|
131864
|
+
let warmupStarted = false;
|
|
131865
|
+
let invalidations = 0;
|
|
131866
|
+
const countInvalidations = () => {
|
|
131867
|
+
registerSessionInvalidationHook(session, () => {
|
|
131868
|
+
invalidations += 1;
|
|
131869
|
+
countInvalidations();
|
|
131870
|
+
});
|
|
131871
|
+
};
|
|
131872
|
+
countInvalidations();
|
|
131873
|
+
const track = (work) => {
|
|
131874
|
+
if (!pending.size)
|
|
131875
|
+
busySince = performance.now();
|
|
131876
|
+
pending.add(work);
|
|
131877
|
+
const release = () => {
|
|
131878
|
+
pending.delete(work);
|
|
131879
|
+
if (!pending.size)
|
|
131880
|
+
busySince = void 0;
|
|
131881
|
+
};
|
|
131882
|
+
work.then(release, release);
|
|
131883
|
+
return work;
|
|
131884
|
+
};
|
|
131885
|
+
const buildsSettled = async () => {
|
|
131886
|
+
while (pending.size)
|
|
131887
|
+
await Promise.allSettled([...pending]);
|
|
131888
|
+
};
|
|
131889
|
+
const load = async (need) => {
|
|
131890
|
+
if (need === "symbolGraph") {
|
|
131891
|
+
await session.loadProject({ symbolGraph: "basic" });
|
|
131892
|
+
} else if (need === "detailedGraph") {
|
|
131893
|
+
await session.loadProject();
|
|
131894
|
+
} else if (need === "duplicates") {
|
|
131895
|
+
await session.loadDuplicateAnalysis?.();
|
|
131896
|
+
} else if (need === "queryIndex") {
|
|
131897
|
+
const snapshot = await session.loadProject({ symbolGraph: "skip" });
|
|
131898
|
+
const { ensureSessionQueryIndex: ensureSessionQueryIndex2 } = await Promise.resolve().then(() => (init_session_store(), session_store_exports));
|
|
131899
|
+
await ensureSessionQueryIndex2(session, snapshot);
|
|
131900
|
+
} else {
|
|
131901
|
+
await session.loadProject({ symbolGraph: "skip" });
|
|
131902
|
+
}
|
|
131903
|
+
};
|
|
131904
|
+
const trackedLoad = (need) => track(load(need));
|
|
131905
|
+
const startWarmup = () => {
|
|
131906
|
+
if (warmupStarted)
|
|
131907
|
+
return;
|
|
131908
|
+
warmupStarted = true;
|
|
131909
|
+
if (!options.warmup.length)
|
|
131910
|
+
return;
|
|
131911
|
+
void track(Promise.all(options.warmup.map(trackedLoad)).then(() => void 0, (error62) => {
|
|
131912
|
+
console.error(`[codegraph] MCP startup warmup failed: ${describeMcpRuntimeError(error62)}`);
|
|
131913
|
+
}));
|
|
131914
|
+
};
|
|
131915
|
+
const describeProgress = (needs, done, waitedMs) => {
|
|
131916
|
+
const elapsedMs2 = Math.round(busySince === void 0 ? waitedMs : performance.now() - busySince);
|
|
131917
|
+
const update = options.progress.latest();
|
|
131918
|
+
if (update) {
|
|
131919
|
+
return {
|
|
131920
|
+
activity: update.activity,
|
|
131921
|
+
...update.total > 0 ? { current: update.current, total: update.total } : {},
|
|
131922
|
+
elapsedMs: elapsedMs2
|
|
131923
|
+
};
|
|
131924
|
+
}
|
|
131925
|
+
const unfinished = needs.find((need) => !done.has(need));
|
|
131926
|
+
return { activity: unfinished ? ACTIVITY[unfinished] : CHECKING_ACTIVITY, elapsedMs: elapsedMs2 };
|
|
131927
|
+
};
|
|
131928
|
+
const waitFor = async (tool, needs, signal, followUp) => {
|
|
131929
|
+
if (signal?.aborted)
|
|
131930
|
+
throw mcpCancellationError(signal);
|
|
131931
|
+
const startedAt = performance.now();
|
|
131932
|
+
let wanted = [...needs];
|
|
131933
|
+
const done = /* @__PURE__ */ new Set();
|
|
131934
|
+
const loadAll = async (list) => {
|
|
131935
|
+
await Promise.all(list.map(async (need) => {
|
|
131936
|
+
await trackedLoad(need);
|
|
131937
|
+
done.add(need);
|
|
131938
|
+
}));
|
|
131939
|
+
};
|
|
131940
|
+
const ready = track((async () => {
|
|
131941
|
+
await checkSessionFreshness(session);
|
|
131942
|
+
for (let round = 0; round < MAX_READINESS_ROUNDS; round += 1) {
|
|
131943
|
+
const loadedAt = invalidations;
|
|
131944
|
+
wanted = [...needs];
|
|
131945
|
+
done.clear();
|
|
131946
|
+
await loadAll(needs);
|
|
131947
|
+
if (followUp) {
|
|
131948
|
+
const later = await followUp();
|
|
131949
|
+
wanted.push(...later);
|
|
131950
|
+
await loadAll(later);
|
|
131951
|
+
}
|
|
131952
|
+
await checkSessionFreshness(session);
|
|
131953
|
+
if (invalidations === loadedAt)
|
|
131954
|
+
return;
|
|
131955
|
+
}
|
|
131956
|
+
})());
|
|
131957
|
+
if (await settleWithinBudget(ready, options.waitMs, signal) === "ready")
|
|
131958
|
+
return;
|
|
131959
|
+
const waitedMs = Math.round(performance.now() - startedAt);
|
|
131960
|
+
const progress = describeProgress(wanted, done, waitedMs);
|
|
131961
|
+
const counts = progress.total === void 0 ? "" : ` ${progress.current ?? 0}/${progress.total}`;
|
|
131962
|
+
throw new McpIndexBuildingError({
|
|
131963
|
+
status: "index_building",
|
|
131964
|
+
tool,
|
|
131965
|
+
message: `Codegraph is still building the index for this project (${progress.activity}${counts}, ${Math.round(progress.elapsedMs / 1e3)}s so far). The build continues in the background; call '${tool}' again to wait for it.`,
|
|
131966
|
+
retryAfterMs: MCP_INDEX_RETRY_AFTER_MS,
|
|
131967
|
+
waitedMs,
|
|
131968
|
+
progress
|
|
131969
|
+
});
|
|
131970
|
+
};
|
|
131971
|
+
return { startWarmup, buildsSettled, waitFor };
|
|
131972
|
+
}
|
|
131973
|
+
var DEFAULT_MCP_INDEX_WAIT_MS, MCP_INDEX_RETRY_AFTER_MS, MAX_MCP_INDEX_WAIT_MS, McpIndexBuildingError, ACTIVITY, CHECKING_ACTIVITY, MAX_READINESS_ROUNDS;
|
|
131974
|
+
var init_index_readiness = __esm({
|
|
131975
|
+
"dist/mcp/index-readiness.js"() {
|
|
131976
|
+
"use strict";
|
|
131977
|
+
init_search();
|
|
131978
|
+
init_session();
|
|
131979
|
+
init_session_lifecycle();
|
|
131980
|
+
init_cancellation();
|
|
131981
|
+
init_stale_install();
|
|
131982
|
+
DEFAULT_MCP_INDEX_WAIT_MS = 15e3;
|
|
131983
|
+
MCP_INDEX_RETRY_AFTER_MS = 1e3;
|
|
131984
|
+
MAX_MCP_INDEX_WAIT_MS = 2147483647;
|
|
131985
|
+
McpIndexBuildingError = class extends Error {
|
|
131986
|
+
result;
|
|
131987
|
+
constructor(result) {
|
|
131988
|
+
super(result.message);
|
|
131989
|
+
this.name = "McpIndexBuildingError";
|
|
131990
|
+
this.result = result;
|
|
131991
|
+
}
|
|
131992
|
+
};
|
|
131993
|
+
ACTIVITY = {
|
|
131994
|
+
index: "Building project index",
|
|
131995
|
+
symbolGraph: "Building symbol graph",
|
|
131996
|
+
queryIndex: "Building search index",
|
|
131997
|
+
detailedGraph: "Building detailed symbol graph",
|
|
131998
|
+
duplicates: "Preparing duplicate analysis"
|
|
131999
|
+
};
|
|
132000
|
+
CHECKING_ACTIVITY = "Checking the project for changed files";
|
|
132001
|
+
MAX_READINESS_ROUNDS = 3;
|
|
132002
|
+
}
|
|
132003
|
+
});
|
|
132004
|
+
|
|
131152
132005
|
// dist/mcp/handlers.js
|
|
131153
132006
|
import fs42 from "node:fs/promises";
|
|
131154
132007
|
import path96 from "node:path";
|
|
131155
132008
|
function assertMcpSessionOptions(options) {
|
|
131156
132009
|
assertNoPrebuiltSessionWithBuildOptions(options, "MCP server options");
|
|
131157
132010
|
}
|
|
131158
|
-
function createCodegraphMcpSession(options, root) {
|
|
132011
|
+
function createCodegraphMcpSession(options, root, buildProgress) {
|
|
131159
132012
|
assertMcpSessionOptions(options);
|
|
131160
|
-
|
|
132013
|
+
if (options.session)
|
|
132014
|
+
return options.session;
|
|
132015
|
+
const onProgress = options.buildOptions?.onProgress;
|
|
132016
|
+
const buildOptions = buildProgress ? {
|
|
132017
|
+
...options.buildOptions,
|
|
132018
|
+
onProgress: (update) => {
|
|
132019
|
+
buildProgress.record(update);
|
|
132020
|
+
onProgress?.(update);
|
|
132021
|
+
}
|
|
132022
|
+
} : options.buildOptions;
|
|
132023
|
+
return createAgentSession({
|
|
131161
132024
|
root,
|
|
131162
|
-
...
|
|
132025
|
+
...buildOptions ? { buildOptions } : {},
|
|
131163
132026
|
freshness: { policy: "auto" }
|
|
131164
132027
|
});
|
|
131165
132028
|
}
|
|
@@ -131170,14 +132033,49 @@ function resolveWatchedCacheDirectory(root, buildOptions) {
|
|
|
131170
132033
|
return void 0;
|
|
131171
132034
|
}
|
|
131172
132035
|
}
|
|
131173
|
-
function
|
|
131174
|
-
|
|
132036
|
+
function resolveStartupWarmupMode(warmup, sessionProvidedExplicitly) {
|
|
132037
|
+
return warmup ?? (sessionProvidedExplicitly ? "off" : "base");
|
|
132038
|
+
}
|
|
132039
|
+
function rebuildSession(session, mode) {
|
|
131175
132040
|
if (mode === "off")
|
|
131176
132041
|
return void 0;
|
|
131177
132042
|
if (mode === "symbols")
|
|
131178
132043
|
return session.loadProject();
|
|
131179
132044
|
return session.loadProject({ symbolGraph: "skip" });
|
|
131180
132045
|
}
|
|
132046
|
+
function warmupNeeds(mode) {
|
|
132047
|
+
if (mode === "off")
|
|
132048
|
+
return [];
|
|
132049
|
+
if (mode === "symbols")
|
|
132050
|
+
return ["symbolGraph", "queryIndex", "detailedGraph"];
|
|
132051
|
+
return ["symbolGraph", "queryIndex"];
|
|
132052
|
+
}
|
|
132053
|
+
function withIndexBudget(handlers, readiness, session) {
|
|
132054
|
+
const budgeted = (tool, handler, needsOf, followUpOf) => async (request, signal) => {
|
|
132055
|
+
const needs = needsOf(request);
|
|
132056
|
+
if (needs)
|
|
132057
|
+
await readiness.waitFor(tool, needs, signal, followUpOf?.(request));
|
|
132058
|
+
return await handler(request, signal);
|
|
132059
|
+
};
|
|
132060
|
+
return {
|
|
132061
|
+
...handlers,
|
|
132062
|
+
search: budgeted("search", handlers.search, searchNeeds),
|
|
132063
|
+
explore: budgeted("explore", handlers.explore, exploreNeeds),
|
|
132064
|
+
orient: budgeted("orient", handlers.orient, () => ["index"]),
|
|
132065
|
+
workspace_symbols: budgeted("workspace_symbols", handlers.workspace_symbols, () => ["index"]),
|
|
132066
|
+
impact: budgeted("impact", handlers.impact, () => ["index"]),
|
|
132067
|
+
// Only a graph context reads the index; the bytes of a file come from disk.
|
|
132068
|
+
get_file: budgeted("get_file", handlers.get_file, (request) => request.includeGraphContext ? ["index"] : void 0),
|
|
132069
|
+
// A `review:` target builds its own report from git and reads no session build. Any other target reads the detailed
|
|
132070
|
+
// symbol graph, and also the duplicate analysis of its duplicate context, except a SQL object, which has none, and
|
|
132071
|
+
// a target that does not resolve, which fails at once. What the target resolves to is known once the detailed
|
|
132072
|
+
// symbol graph is loaded, so that decision follows it.
|
|
132073
|
+
packet_get: budgeted("packet_get", handlers.packet_get, (request) => request.target.startsWith("review:") ? [] : ["detailedGraph"], (request) => request.target.startsWith("review:") ? void 0 : async () => {
|
|
132074
|
+
const { kind } = await resolveCodegraphTargetWithSession(session, { target: request.target });
|
|
132075
|
+
return kind === "sql_object" || kind === "not_found" ? [] : ["duplicates"];
|
|
132076
|
+
})
|
|
132077
|
+
};
|
|
132078
|
+
}
|
|
131181
132079
|
function withToolActivity(handlers, noteActivity) {
|
|
131182
132080
|
return new Proxy(handlers, {
|
|
131183
132081
|
get(target, property, receiver) {
|
|
@@ -131191,19 +132089,25 @@ function withToolActivity(handlers, noteActivity) {
|
|
|
131191
132089
|
}
|
|
131192
132090
|
});
|
|
131193
132091
|
}
|
|
131194
|
-
|
|
132092
|
+
function createCodegraphMcpResources(options) {
|
|
131195
132093
|
const root = path96.resolve(options.root);
|
|
131196
132094
|
const sessionProvidedExplicitly = options.session !== void 0;
|
|
131197
|
-
const { warmup, host, port, onHttpListen, watch, watchDebounceMs, watchMinRefreshIntervalMs, watchIdleMs, ...handlerOptions } = options;
|
|
132095
|
+
const { warmup, host, port, onHttpListen, watch, watchDebounceMs, watchMinRefreshIntervalMs, watchIdleMs, mcpIndexWaitMs, ...handlerOptions } = options;
|
|
131198
132096
|
void host;
|
|
131199
132097
|
void port;
|
|
131200
132098
|
void onHttpListen;
|
|
131201
132099
|
assertMcpWatchMs("watchDebounceMs", watchDebounceMs);
|
|
131202
132100
|
assertMcpWatchMs("watchMinRefreshIntervalMs", watchMinRefreshIntervalMs);
|
|
131203
132101
|
assertMcpWatchMs("watchIdleMs", watchIdleMs);
|
|
131204
|
-
const
|
|
131205
|
-
|
|
131206
|
-
const
|
|
132102
|
+
const indexWaitMs = assertMcpIndexWait(mcpIndexWaitMs ?? DEFAULT_MCP_INDEX_WAIT_MS);
|
|
132103
|
+
const buildProgress = createMcpBuildProgress();
|
|
132104
|
+
const session = createCodegraphMcpSession(options, root, buildProgress);
|
|
132105
|
+
const readiness = createMcpIndexReadiness(session, {
|
|
132106
|
+
waitMs: indexWaitMs,
|
|
132107
|
+
warmup: warmupNeeds(resolveStartupWarmupMode(warmup, sessionProvidedExplicitly)),
|
|
132108
|
+
progress: buildProgress
|
|
132109
|
+
});
|
|
132110
|
+
const { handlers, runExclusive } = createCodegraphMcpHandlersForSession({ ...handlerOptions, root }, session, readiness);
|
|
131207
132111
|
const watcher = sessionProvidedExplicitly || watch === false ? void 0 : createWatchController(session, {
|
|
131208
132112
|
root,
|
|
131209
132113
|
runExclusive,
|
|
@@ -131216,10 +132120,12 @@ async function createWarmedCodegraphMcpResources(options) {
|
|
|
131216
132120
|
return {
|
|
131217
132121
|
handlers: watcher ? withToolActivity(handlers, watcher.noteActivity) : handlers,
|
|
131218
132122
|
session,
|
|
131219
|
-
closeWatcher: () => watcher?.close() ?? Promise.resolve()
|
|
132123
|
+
closeWatcher: () => watcher?.close() ?? Promise.resolve(),
|
|
132124
|
+
startWarmup: readiness.startWarmup,
|
|
132125
|
+
buildsSettled: readiness.buildsSettled
|
|
131220
132126
|
};
|
|
131221
132127
|
}
|
|
131222
|
-
function createCodegraphMcpHandlersForSession(options, session) {
|
|
132128
|
+
function createCodegraphMcpHandlersForSession(options, session, readiness) {
|
|
131223
132129
|
const root = path96.resolve(options.root);
|
|
131224
132130
|
const readOnly = options.readOnly ?? true;
|
|
131225
132131
|
const realRoot = fs42.realpath(root);
|
|
@@ -131672,20 +132578,30 @@ function createCodegraphMcpHandlersForSession(options, session) {
|
|
|
131672
132578
|
...DEFAULT_BOUNDED_IMPACT_BUDGETS
|
|
131673
132579
|
});
|
|
131674
132580
|
}),
|
|
131675
|
-
review: async (request
|
|
131676
|
-
const
|
|
132581
|
+
review: async (request, signal) => {
|
|
132582
|
+
const reviewOptions = {
|
|
131677
132583
|
...options.buildOptions,
|
|
131678
132584
|
gitBase: request.base,
|
|
131679
132585
|
gitHead: request.head,
|
|
131680
132586
|
...request.reviewDepth !== void 0 ? { reviewDepth: request.reviewDepth } : {}
|
|
131681
|
-
}
|
|
131682
|
-
|
|
131683
|
-
|
|
131684
|
-
|
|
131685
|
-
...
|
|
132587
|
+
};
|
|
132588
|
+
const changes = await collectReviewChanges(root, reviewOptions);
|
|
132589
|
+
if (!changes.changedFiles.size) {
|
|
132590
|
+
const report2 = await buildReviewReport(root, reviewOptions, { changes });
|
|
132591
|
+
return { ...boundReviewReportForTransport(report2), freshness: { state: "fresh" } };
|
|
132592
|
+
}
|
|
132593
|
+
await readiness?.waitFor("review", ["index", "duplicates"], signal);
|
|
132594
|
+
return await withFreshness(async () => {
|
|
132595
|
+
const report2 = await buildReviewReport(root, reviewOptions, {
|
|
132596
|
+
changes,
|
|
132597
|
+
...session.loadProject ? {
|
|
132598
|
+
loadIndex: async () => (await session.loadProject({ symbolGraph: "skip" })).index
|
|
132599
|
+
} : {},
|
|
132600
|
+
...session.loadDuplicateAnalysis ? { loadDuplicateAnalysis: session.loadDuplicateAnalysis } : {}
|
|
132601
|
+
});
|
|
132602
|
+
return boundReviewReportForTransport(report2);
|
|
131686
132603
|
});
|
|
131687
|
-
|
|
131688
|
-
})
|
|
132604
|
+
}
|
|
131689
132605
|
};
|
|
131690
132606
|
const artifactHandlers = {
|
|
131691
132607
|
query_sqlite: async (request, executionOptions) => {
|
|
@@ -131721,7 +132637,7 @@ function createCodegraphMcpHandlersForSession(options, session) {
|
|
|
131721
132637
|
sqlitePath = configuredSqlitePath;
|
|
131722
132638
|
sqliteOutDir = configuredSqliteOutDir;
|
|
131723
132639
|
sqliteCanRefresh = configuredSqliteCanRefresh;
|
|
131724
|
-
await
|
|
132640
|
+
await rebuildSession(session, warmup);
|
|
131725
132641
|
})();
|
|
131726
132642
|
refreshPromise = refresh;
|
|
131727
132643
|
try {
|
|
@@ -131766,8 +132682,14 @@ function createCodegraphMcpHandlersForSession(options, session) {
|
|
|
131766
132682
|
session.invalidate();
|
|
131767
132683
|
}
|
|
131768
132684
|
};
|
|
132685
|
+
const handlers = {
|
|
132686
|
+
...searchHandlers,
|
|
132687
|
+
...navigationHandlers,
|
|
132688
|
+
...reviewHandlers,
|
|
132689
|
+
...artifactHandlers
|
|
132690
|
+
};
|
|
131769
132691
|
return {
|
|
131770
|
-
handlers:
|
|
132692
|
+
handlers: readiness ? withIndexBudget(handlers, readiness, session) : handlers,
|
|
131771
132693
|
runExclusive: withArtifactWriteLock
|
|
131772
132694
|
};
|
|
131773
132695
|
}
|
|
@@ -131796,6 +132718,7 @@ var init_handlers = __esm({
|
|
|
131796
132718
|
init_impact();
|
|
131797
132719
|
init_budgets();
|
|
131798
132720
|
init_review2();
|
|
132721
|
+
init_changes();
|
|
131799
132722
|
init_types4();
|
|
131800
132723
|
init_sqlite();
|
|
131801
132724
|
init_bounds();
|
|
@@ -131812,6 +132735,7 @@ var init_handlers = __esm({
|
|
|
131812
132735
|
init_runtime_identity();
|
|
131813
132736
|
init_security();
|
|
131814
132737
|
init_project_watcher();
|
|
132738
|
+
init_index_readiness();
|
|
131815
132739
|
MAX_MCP_FRESHNESS_CHANGED_FILES = 25;
|
|
131816
132740
|
MAX_MCP_FRESHNESS_RETRIES = 3;
|
|
131817
132741
|
SQLITE_ARTIFACT_STAT_CONCURRENCY = 64;
|
|
@@ -135209,6 +136133,10 @@ function createCodegraphMcpProtocolServerWithTracker(handlers, runtimeIdentity,
|
|
|
135209
136133
|
} catch (error62) {
|
|
135210
136134
|
if (error62 instanceof ProtocolError || toolCallAbort.signal.aborted)
|
|
135211
136135
|
throw error62;
|
|
136136
|
+
if (error62 instanceof McpIndexBuildingError) {
|
|
136137
|
+
await emitFirstToolCallVisibility("info", 1, error62.result.message);
|
|
136138
|
+
return toToolResult(error62.result);
|
|
136139
|
+
}
|
|
135212
136140
|
return toToolErrorResult(error62);
|
|
135213
136141
|
}
|
|
135214
136142
|
} finally {
|
|
@@ -135320,16 +136248,10 @@ function awaitMcpToolOperation(signal, operation, onSettled) {
|
|
|
135320
136248
|
function withAbortSignal(signal, operation) {
|
|
135321
136249
|
if (!signal)
|
|
135322
136250
|
return operation;
|
|
135323
|
-
const cancellationError = () => {
|
|
135324
|
-
const reason = signal.reason;
|
|
135325
|
-
if (reason instanceof Error && reason.name !== "AbortError")
|
|
135326
|
-
return reason;
|
|
135327
|
-
return new Error("MCP tool call was cancelled.");
|
|
135328
|
-
};
|
|
135329
136251
|
if (signal.aborted)
|
|
135330
|
-
return Promise.reject(
|
|
136252
|
+
return Promise.reject(mcpCancellationError(signal));
|
|
135331
136253
|
const cancellation = Promise.withResolvers();
|
|
135332
|
-
const onAbort = () => cancellation.reject(
|
|
136254
|
+
const onAbort = () => cancellation.reject(mcpCancellationError(signal));
|
|
135333
136255
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
135334
136256
|
return Promise.race([operation, cancellation.promise]).finally(() => signal.removeEventListener("abort", onAbort));
|
|
135335
136257
|
}
|
|
@@ -135499,7 +136421,7 @@ function firstDuplicateFile(arguments_) {
|
|
|
135499
136421
|
return files.find((file2) => typeof file2 === "string") ?? ".";
|
|
135500
136422
|
}
|
|
135501
136423
|
function toToolErrorResult(error62) {
|
|
135502
|
-
const message =
|
|
136424
|
+
const message = describeMcpRuntimeError(error62).replace(/(?:[A-Za-z]:)?[/\\][^'"\n]*?(?=(?:[/\\][^'"\n]*)?['"]|$)/g, "<path>");
|
|
135503
136425
|
return { isError: true, content: [{ type: "text", text: message }] };
|
|
135504
136426
|
}
|
|
135505
136427
|
function getToolCallProgressToken(params) {
|
|
@@ -135521,12 +136443,19 @@ function parseMcpToolInput(schema, input2, toolName) {
|
|
|
135521
136443
|
return parsed.data;
|
|
135522
136444
|
throw new ProtocolError(ProtocolErrorCode.InvalidParams, formatMcpInvalidParams(toolName, parsed.error));
|
|
135523
136445
|
}
|
|
136446
|
+
function describeReceivedValue(value) {
|
|
136447
|
+
if (value === null)
|
|
136448
|
+
return "null";
|
|
136449
|
+
if (value === void 0)
|
|
136450
|
+
return "nothing (the field is missing)";
|
|
136451
|
+
return typeof value;
|
|
136452
|
+
}
|
|
135524
136453
|
function createCodegraphMcpStdioTransport(input2, output2) {
|
|
135525
136454
|
return new StdioServerTransport(createParseErrorReportingStdin(input2, output2), output2, {
|
|
135526
136455
|
maxBufferSize: MAX_MCP_STDIO_FRAME_BYTES
|
|
135527
136456
|
});
|
|
135528
136457
|
}
|
|
135529
|
-
var DEFAULT_MCP_TOOL_TIMEOUT_MS, MAX_MCP_TOOL_TIMEOUT_MS, MAX_MCP_STDIO_FRAME_BYTES, DEFAULT_MCP_TOOL_CONCURRENCY, mcpProgressTokenSchema, toolCallMetaSchema, searchSchema, workspaceSymbolsSchema, renamePreviewSchema, refactorPlanSchema, callHierarchySchema, callsSchema, typeHierarchySchema, typeHierarchyUnifiedSchema, implementationsSchema, exploreSchema, orientSchema, packetGetSchema, getFileSchema, handleSchema, navigationSchema, refsSchema, fileGraphSchema, fileDepsUnifiedSchema, pathSchema, gitRangeSchema, reviewSchema, querySqliteSchema, refreshIndexSchema, artifactBuildSchema;
|
|
136458
|
+
var DEFAULT_MCP_TOOL_TIMEOUT_MS, MAX_MCP_TOOL_TIMEOUT_MS, MAX_MCP_STDIO_FRAME_BYTES, DEFAULT_MCP_TOOL_CONCURRENCY, mcpProgressTokenSchema, toolCallMetaSchema, searchSchema, workspaceSymbolsSchema, renamePreviewSchema, refactorPlanSchema, callHierarchySchema, callsSchema, typeHierarchySchema, typeHierarchyUnifiedSchema, implementationsSchema, exploreSchema, orientSchema, packetGetSchema, getFilePathSchema, getFileSchema, handleSchema, navigationSchema, refsSchema, fileGraphSchema, fileDepsUnifiedSchema, pathSchema, gitRangeSchema, reviewSchema, querySqliteSchema, refreshIndexSchema, artifactBuildSchema;
|
|
135530
136459
|
var init_protocol = __esm({
|
|
135531
136460
|
"dist/mcp/protocol.js"() {
|
|
135532
136461
|
"use strict";
|
|
@@ -135541,7 +136470,10 @@ var init_protocol = __esm({
|
|
|
135541
136470
|
init_tools();
|
|
135542
136471
|
init_runtime();
|
|
135543
136472
|
init_runtime_identity();
|
|
136473
|
+
init_cancellation();
|
|
136474
|
+
init_index_readiness();
|
|
135544
136475
|
init_legacy_sessions();
|
|
136476
|
+
init_stale_install();
|
|
135545
136477
|
DEFAULT_MCP_TOOL_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
135546
136478
|
MAX_MCP_TOOL_TIMEOUT_MS = 2147483647;
|
|
135547
136479
|
MAX_MCP_STDIO_FRAME_BYTES = 10 * 1024 * 1024;
|
|
@@ -135620,8 +136552,11 @@ var init_protocol = __esm({
|
|
|
135620
136552
|
maxSnippets: external_exports.number().int().positive().max(50).optional(),
|
|
135621
136553
|
maxDuplicates: external_exports.number().int().positive().max(20).optional()
|
|
135622
136554
|
}).strict();
|
|
136555
|
+
getFilePathSchema = external_exports.string({
|
|
136556
|
+
error: (issue2) => `expected a project-relative file path string, received ${describeReceivedValue(issue2.input)}`
|
|
136557
|
+
});
|
|
135623
136558
|
getFileSchema = external_exports.object({
|
|
135624
|
-
file:
|
|
136559
|
+
file: getFilePathSchema,
|
|
135625
136560
|
offset: external_exports.number().int().positive().optional(),
|
|
135626
136561
|
limit: external_exports.number().int().positive().max(MAX_FILE_VIEW_LINES).optional(),
|
|
135627
136562
|
maxBytes: external_exports.number().int().positive().max(MAX_FILE_VIEW_BYTES).optional(),
|
|
@@ -135762,7 +136697,7 @@ async function startCodegraphMcpHttpServer(options) {
|
|
|
135762
136697
|
const configuredMcpToolTimeout = options.mcpToolTimeoutMs === void 0 ? DEFAULT_MCP_TOOL_TIMEOUT_MS : options.mcpToolTimeoutMs;
|
|
135763
136698
|
const mcpToolTimeoutMs = assertMcpToolTimeout(configuredMcpToolTimeout);
|
|
135764
136699
|
const host = options.host ?? "127.0.0.1", lifecycleHealth = await Promise.resolve().then(() => (init_lifecycle_health(), lifecycle_health_exports));
|
|
135765
|
-
const { handlers, session, closeWatcher } =
|
|
136700
|
+
const { handlers, session, closeWatcher, startWarmup, buildsSettled } = createCodegraphMcpResources(options);
|
|
135766
136701
|
const runtimeIdentity = options.runtimeIdentity ?? captureCodegraphRuntimeIdentity(getCurrentNativeBindingOrigin());
|
|
135767
136702
|
const installedVersionChecker = createInstalledVersionChecker(runtimeIdentity, { warn: () => {
|
|
135768
136703
|
} });
|
|
@@ -135796,6 +136731,7 @@ async function startCodegraphMcpHttpServer(options) {
|
|
|
135796
136731
|
} finally {
|
|
135797
136732
|
await protocolFactory.drain();
|
|
135798
136733
|
await watcherClosed;
|
|
136734
|
+
await buildsSettled();
|
|
135799
136735
|
session.invalidate();
|
|
135800
136736
|
}
|
|
135801
136737
|
})();
|
|
@@ -135837,6 +136773,7 @@ async function startCodegraphMcpHttpServer(options) {
|
|
|
135837
136773
|
const urlHost = formatHostForUrl(host);
|
|
135838
136774
|
const url2 = `http://${urlHost}:${actualPort}${MCP_HTTP_PATH}`;
|
|
135839
136775
|
allowedHostHeaders = buildAllowedHostHeaders(host, actualPort);
|
|
136776
|
+
startWarmup();
|
|
135840
136777
|
return {
|
|
135841
136778
|
server,
|
|
135842
136779
|
host,
|
|
@@ -135953,7 +136890,7 @@ async function serveCodegraphMcp(options) {
|
|
|
135953
136890
|
await waitForHttpServerClose(started.server);
|
|
135954
136891
|
return;
|
|
135955
136892
|
}
|
|
135956
|
-
const { handlers, session, closeWatcher } =
|
|
136893
|
+
const { handlers, session, closeWatcher, startWarmup, buildsSettled } = createCodegraphMcpResources(options);
|
|
135957
136894
|
const runtimeIdentity = options.runtimeIdentity ?? captureCodegraphRuntimeIdentity(getCurrentNativeBindingOrigin());
|
|
135958
136895
|
const protocolFactory = createCodegraphMcpProtocolFactory(handlers, runtimeIdentity, options.mcpToolConcurrency ?? DEFAULT_MCP_TOOL_CONCURRENCY, mcpToolTimeoutMs);
|
|
135959
136896
|
const transport = createCodegraphMcpStdioTransport(process.stdin, process.stdout);
|
|
@@ -135964,6 +136901,7 @@ async function serveCodegraphMcp(options) {
|
|
|
135964
136901
|
console.error(`[codegraph] MCP stdio error: ${error62.message}`);
|
|
135965
136902
|
}
|
|
135966
136903
|
});
|
|
136904
|
+
startWarmup();
|
|
135967
136905
|
const idleTimeoutMs = options.idleTimeoutMs ?? DEFAULT_MCP_STDIO_IDLE_TIMEOUT_MS;
|
|
135968
136906
|
try {
|
|
135969
136907
|
await awaitStdioMcpLifecycle(handle, {
|
|
@@ -135977,6 +136915,7 @@ async function serveCodegraphMcp(options) {
|
|
|
135977
136915
|
const watcherClosed = closeWatcher();
|
|
135978
136916
|
await protocolFactory.drain();
|
|
135979
136917
|
await watcherClosed;
|
|
136918
|
+
await buildsSettled();
|
|
135980
136919
|
session.invalidate();
|
|
135981
136920
|
}
|
|
135982
136921
|
process.exitCode = 0;
|
|
@@ -135997,6 +136936,7 @@ var init_server = __esm({
|
|
|
135997
136936
|
init_protocol();
|
|
135998
136937
|
init_http_transport();
|
|
135999
136938
|
init_http_transport();
|
|
136939
|
+
init_index_readiness();
|
|
136000
136940
|
init_legacy_sessions();
|
|
136001
136941
|
}
|
|
136002
136942
|
});
|
|
@@ -136015,9 +136955,11 @@ async function handleMcpServeCommand(context) {
|
|
|
136015
136955
|
const artifactPath = context.getOpt("--artifact");
|
|
136016
136956
|
let port;
|
|
136017
136957
|
let idleTimeoutMs;
|
|
136958
|
+
let indexWaitMs;
|
|
136018
136959
|
try {
|
|
136019
136960
|
port = parseOptionalBoundedIntegerOption(context.getOpt("--port"), "--port", 0, 65535);
|
|
136020
136961
|
idleTimeoutMs = parseOptionalBoundedIntegerOption(context.getOpt("--idle-timeout-ms"), "--idle-timeout-ms", 0, 24 * 60 * 60 * 1e3);
|
|
136962
|
+
indexWaitMs = parseOptionalBoundedIntegerOption(context.getOpt("--index-wait-ms"), "--index-wait-ms", 0, MAX_MCP_INDEX_WAIT_MS);
|
|
136021
136963
|
} catch (error62) {
|
|
136022
136964
|
exitWithError(context, error62, 2);
|
|
136023
136965
|
}
|
|
@@ -136045,6 +136987,7 @@ async function handleMcpServeCommand(context) {
|
|
|
136045
136987
|
warmup,
|
|
136046
136988
|
...context.hasFlag("--no-watch") ? { watch: false } : {},
|
|
136047
136989
|
...idleTimeoutMs !== void 0 ? { idleTimeoutMs } : {},
|
|
136990
|
+
...indexWaitMs !== void 0 ? { mcpIndexWaitMs: indexWaitMs } : {},
|
|
136048
136991
|
onHttpListen: (info) => {
|
|
136049
136992
|
context.writeStderrLine(`Codegraph MCP HTTP server listening at ${info.url}`);
|
|
136050
136993
|
}
|
|
@@ -136070,6 +137013,7 @@ var init_mcp = __esm({
|
|
|
136070
137013
|
"dist/cli/mcp.js"() {
|
|
136071
137014
|
"use strict";
|
|
136072
137015
|
init_server();
|
|
137016
|
+
init_index_readiness();
|
|
136073
137017
|
init_help();
|
|
136074
137018
|
init_options();
|
|
136075
137019
|
init_context();
|
|
@@ -136898,6 +137842,7 @@ var init_server2 = __esm({
|
|
|
136898
137842
|
"--host",
|
|
136899
137843
|
"--ignore-glob",
|
|
136900
137844
|
"--include-glob",
|
|
137845
|
+
"--index-wait-ms",
|
|
136901
137846
|
"--port",
|
|
136902
137847
|
"--resolution-hint",
|
|
136903
137848
|
"--startup-timeout-ms",
|
|
@@ -136928,6 +137873,7 @@ var init_server2 = __esm({
|
|
|
136928
137873
|
"--cache-dir",
|
|
136929
137874
|
"--include-glob",
|
|
136930
137875
|
"--ignore-glob",
|
|
137876
|
+
"--index-wait-ms",
|
|
136931
137877
|
"--resolution-hint",
|
|
136932
137878
|
"--threads"
|
|
136933
137879
|
];
|
|
@@ -137499,7 +138445,7 @@ __export(graph_exports, {
|
|
|
137499
138445
|
});
|
|
137500
138446
|
import fs44 from "node:fs";
|
|
137501
138447
|
import fsp43 from "node:fs/promises";
|
|
137502
|
-
import { performance as
|
|
138448
|
+
import { performance as performance16 } from "node:perf_hooks";
|
|
137503
138449
|
function resolveGraphCacheMode(cache) {
|
|
137504
138450
|
return cache ?? "disk";
|
|
137505
138451
|
}
|
|
@@ -137636,11 +138582,11 @@ function stabilizeSymbolGraph(graph) {
|
|
|
137636
138582
|
}
|
|
137637
138583
|
async function handleGraphCommand(context) {
|
|
137638
138584
|
const commandReport = context.reportEnabled ? { command: "graph", timings: {} } : void 0;
|
|
137639
|
-
const commandStart =
|
|
137640
|
-
const resolveStart =
|
|
138585
|
+
const commandStart = performance16.now();
|
|
138586
|
+
const resolveStart = performance16.now();
|
|
137641
138587
|
const files = await context.resolveFiles();
|
|
137642
138588
|
if (commandReport) {
|
|
137643
|
-
commandReport.timings.resolveFilesMs = Math.round(
|
|
138589
|
+
commandReport.timings.resolveFilesMs = Math.round(performance16.now() - resolveStart);
|
|
137644
138590
|
}
|
|
137645
138591
|
const hasExplicitSymbolFlag = context.hasFlag("--symbols") || context.hasFlag("--symbols-only") || context.hasFlag("--symbols-detailed");
|
|
137646
138592
|
const outputArg = context.getOpt("--output") ?? context.getOpt("--out");
|
|
@@ -137682,7 +138628,7 @@ async function handleGraphCommand(context) {
|
|
|
137682
138628
|
const finalizeReport = async () => {
|
|
137683
138629
|
if (!commandReport)
|
|
137684
138630
|
return;
|
|
137685
|
-
commandReport.timings.commandMs = Math.round(
|
|
138631
|
+
commandReport.timings.commandMs = Math.round(performance16.now() - commandStart);
|
|
137686
138632
|
commandReport.timings.totalMs = commandReport.timings.commandMs;
|
|
137687
138633
|
await context.writeCommandReport(commandReport, context.reportFile);
|
|
137688
138634
|
};
|
|
@@ -137915,7 +138861,7 @@ var cli_exports = {};
|
|
|
137915
138861
|
__export(cli_exports, {
|
|
137916
138862
|
handleIndexCommand: () => handleIndexCommand
|
|
137917
138863
|
});
|
|
137918
|
-
import { performance as
|
|
138864
|
+
import { performance as performance17 } from "node:perf_hooks";
|
|
137919
138865
|
function formatIndexOutput(output2) {
|
|
137920
138866
|
const lines = [`Indexed ${output2.files} file(s) with ${output2.edges} edge(s).`];
|
|
137921
138867
|
if (!isAnalysisComplete(output2.analysis)) {
|
|
@@ -137933,16 +138879,16 @@ function formatIndexOutput(output2) {
|
|
|
137933
138879
|
async function handleIndexCommand(context) {
|
|
137934
138880
|
const verbose = context.hasFlag("--verbose");
|
|
137935
138881
|
const commandReport = context.reportEnabled ? { command: "index", timings: {} } : void 0;
|
|
137936
|
-
const commandStart =
|
|
138882
|
+
const commandStart = performance17.now();
|
|
137937
138883
|
const shouldWriteManifest = !context.includeRootsAbs.length && !context.gitBase && !context.changedSince;
|
|
137938
138884
|
const hasCliDiscoveryGlob = context.getOpt("--include-glob") !== void 0 || context.getOpt("--ignore-glob") !== void 0;
|
|
137939
138885
|
const needsResolvedFiles = !shouldWriteManifest || hasCliDiscoveryGlob;
|
|
137940
138886
|
let files = [];
|
|
137941
138887
|
if (needsResolvedFiles) {
|
|
137942
|
-
const resolveStart =
|
|
138888
|
+
const resolveStart = performance17.now();
|
|
137943
138889
|
files = await context.resolveFiles();
|
|
137944
138890
|
if (commandReport) {
|
|
137945
|
-
commandReport.timings.resolveFilesMs = Math.round(
|
|
138891
|
+
commandReport.timings.resolveFilesMs = Math.round(performance17.now() - resolveStart);
|
|
137946
138892
|
}
|
|
137947
138893
|
}
|
|
137948
138894
|
const threads = parseNonNegativeIntegerOption(context.getOpt("--threads"), "--threads", 0);
|
|
@@ -138003,7 +138949,7 @@ async function handleIndexCommand(context) {
|
|
|
138003
138949
|
}
|
|
138004
138950
|
}
|
|
138005
138951
|
if (commandReport) {
|
|
138006
|
-
commandReport.timings.commandMs = Math.round(
|
|
138952
|
+
commandReport.timings.commandMs = Math.round(performance17.now() - commandStart);
|
|
138007
138953
|
commandReport.timings.totalMs = commandReport.timings.commandMs;
|
|
138008
138954
|
await context.writeCommandReport(commandReport, context.reportFile);
|
|
138009
138955
|
}
|
|
@@ -138810,6 +139756,7 @@ async function cleanupTempDir(dir) {
|
|
|
138810
139756
|
async function resolveGitCommit(root, ref) {
|
|
138811
139757
|
const rev = `${ref}^{commit}`;
|
|
138812
139758
|
const { stdout } = await execFileAsync("git", ["rev-parse", "--verify", "--quiet", "--end-of-options", rev], {
|
|
139759
|
+
windowsHide: true,
|
|
138813
139760
|
cwd: root,
|
|
138814
139761
|
env: process.env
|
|
138815
139762
|
});
|
|
@@ -138824,9 +139771,16 @@ async function materializeGitRef(root, ref, prefix) {
|
|
|
138824
139771
|
return { root };
|
|
138825
139772
|
const tempRoot = await fsp45.mkdtemp(path101.join(os12.tmpdir(), prefix));
|
|
138826
139773
|
try {
|
|
138827
|
-
await execFileAsync("git", ["clone", "--quiet", "--no-checkout", root, tempRoot], {
|
|
139774
|
+
await execFileAsync("git", ["clone", "--quiet", "--no-checkout", root, tempRoot], {
|
|
139775
|
+
windowsHide: true,
|
|
139776
|
+
env: process.env
|
|
139777
|
+
});
|
|
138828
139778
|
const checkoutCommit = await resolveGitCommit(root, checkoutRef);
|
|
138829
|
-
await execFileAsync("git", ["checkout", "--quiet", checkoutCommit], {
|
|
139779
|
+
await execFileAsync("git", ["checkout", "--quiet", checkoutCommit], {
|
|
139780
|
+
windowsHide: true,
|
|
139781
|
+
cwd: tempRoot,
|
|
139782
|
+
env: process.env
|
|
139783
|
+
});
|
|
138830
139784
|
return { root: tempRoot, cleanup: tempRoot };
|
|
138831
139785
|
} catch (error62) {
|
|
138832
139786
|
await cleanupTempDir(tempRoot);
|
|
@@ -139066,6 +140020,8 @@ function getOptionWithProfileDefault(context, optionName2, profile, cleanupDefau
|
|
|
139066
140020
|
function parseDuplicateDetectionOptions(context, profile) {
|
|
139067
140021
|
const minConfidence = parseConfidenceOption(getOptionWithProfileDefault(context, "--min-confidence", profile, "medium"));
|
|
139068
140022
|
const minTokens = parsePositiveIntegerOption(getOptionWithProfileDefault(context, "--min-tokens", profile, "80"), "--min-tokens", 40);
|
|
140023
|
+
const maxCandidatePairsRaw = context.getOpt("--max-candidate-pairs");
|
|
140024
|
+
const maxCandidatePairs = maxCandidatePairsRaw === void 0 ? void 0 : parseBoundedIntegerOption(maxCandidatePairsRaw, "--max-candidate-pairs", DEFAULT_MAX_CANDIDATE_PAIRS, 1, MAX_CANDIDATE_PAIRS_LIMIT);
|
|
139069
140025
|
const options = {
|
|
139070
140026
|
projectRoot: context.projectRootFs,
|
|
139071
140027
|
files: context.files,
|
|
@@ -139074,6 +140030,7 @@ function parseDuplicateDetectionOptions(context, profile) {
|
|
|
139074
140030
|
minTokens,
|
|
139075
140031
|
maxTokens: parsePositiveIntegerOption(context.getOpt("--max-tokens"), "--max-tokens", 800),
|
|
139076
140032
|
maxBucketSize: parsePositiveIntegerOption(context.getOpt("--max-bucket-size"), "--max-bucket-size", 200),
|
|
140033
|
+
...maxCandidatePairs !== void 0 ? { maxCandidatePairs } : {},
|
|
139077
140034
|
...context.hasFlag("--include-same-file") ? { includeSameFile: true } : {},
|
|
139078
140035
|
...context.hasFlag("--include-small") ? { includeSmall: true } : {},
|
|
139079
140036
|
...context.hasFlag("--raw-pairs") ? { includeRawPairs: true } : {}
|
|
@@ -139293,6 +140250,10 @@ function formatPrettyDuplicates(result, sortMode, options) {
|
|
|
139293
140250
|
`Candidate pairs compared: ${result.stats.comparedPairs}/${result.stats.candidatePairs}`,
|
|
139294
140251
|
"Family annotations are heuristic and derived from the displayed duplicate pair."
|
|
139295
140252
|
];
|
|
140253
|
+
const budget = result.stats.candidatePairBudget;
|
|
140254
|
+
if (budget) {
|
|
140255
|
+
lines.push(`Candidate pair limit reached: kept ${budget.limit}, skipped ${budget.skipped}. Results are partial; raise --max-candidate-pairs or lower --max-bucket-size.`);
|
|
140256
|
+
}
|
|
139296
140257
|
const omitted = formatOmittedCounts(result);
|
|
139297
140258
|
if (result.filteredCounts?.cleanupProfileGroups) {
|
|
139298
140259
|
lines.push(`Filtered by cleanup profile: ${result.filteredCounts.cleanupProfileGroups}`);
|
|
@@ -139397,6 +140358,10 @@ async function handleDuplicatesCommand(context) {
|
|
|
139397
140358
|
const boundedLimit = Math.max(requestedLimit, Math.min(ACTIONABILITY_SORT_MAX_CANDIDATES, requestedLimit * ACTIONABILITY_SORT_OVERFETCH_MULTIPLIER));
|
|
139398
140359
|
options.limit = boundedLimit;
|
|
139399
140360
|
}
|
|
140361
|
+
if (context.progressHandler)
|
|
140362
|
+
options.onProgress = context.progressHandler;
|
|
140363
|
+
if (context.progressStartedAt !== void 0)
|
|
140364
|
+
options.progressStartedAt = context.progressStartedAt;
|
|
139400
140365
|
const index = await context.loadCurrentIndex();
|
|
139401
140366
|
const result = await findDuplicates(index, options);
|
|
139402
140367
|
const sorted = sortedResult(result, sortMode, requestedLimit, profile);
|
|
@@ -140962,7 +141927,7 @@ var review_exports = {};
|
|
|
140962
141927
|
__export(review_exports, {
|
|
140963
141928
|
handleReviewCommand: () => handleReviewCommand
|
|
140964
141929
|
});
|
|
140965
|
-
import { performance as
|
|
141930
|
+
import { performance as performance18 } from "node:perf_hooks";
|
|
140966
141931
|
import path102 from "node:path";
|
|
140967
141932
|
function parseReviewDepth(value) {
|
|
140968
141933
|
if (value === "minimal" || value === "standard" || value === "deep") {
|
|
@@ -141154,7 +142119,7 @@ async function collectReviewDuplicateSummary(input2) {
|
|
|
141154
142119
|
});
|
|
141155
142120
|
}
|
|
141156
142121
|
async function handleReviewCommand(context) {
|
|
141157
|
-
const commandStart =
|
|
142122
|
+
const commandStart = performance18.now();
|
|
141158
142123
|
const changedSince = context.getOpt("--changed-since");
|
|
141159
142124
|
const base = context.getOpt("--base") ?? (changedSince === void 0 ? "HEAD" : void 0);
|
|
141160
142125
|
const head = context.getOpt("--head") ?? (changedSince === void 0 ? "WORKTREE" : void 0);
|
|
@@ -141246,7 +142211,7 @@ async function handleReviewCommand(context) {
|
|
|
141246
142211
|
context.writeJSONLine(report2);
|
|
141247
142212
|
}
|
|
141248
142213
|
if (context.commandReport) {
|
|
141249
|
-
context.commandReport.timings.commandMs = Math.round(
|
|
142214
|
+
context.commandReport.timings.commandMs = Math.round(performance18.now() - commandStart);
|
|
141250
142215
|
context.commandReport.timings.totalMs = context.commandReport.timings.commandMs;
|
|
141251
142216
|
await context.writeCommandReport(context.commandReport, context.reportFile);
|
|
141252
142217
|
}
|
|
@@ -141561,7 +142526,7 @@ __export(inspect_exports, {
|
|
|
141561
142526
|
handleHotspotsCommand: () => handleHotspotsCommand,
|
|
141562
142527
|
handleInspectCommand: () => handleInspectCommand
|
|
141563
142528
|
});
|
|
141564
|
-
import { performance as
|
|
142529
|
+
import { performance as performance19 } from "node:perf_hooks";
|
|
141565
142530
|
import fs46 from "node:fs";
|
|
141566
142531
|
import path103 from "node:path";
|
|
141567
142532
|
function defaultCacheIndexPath(projectRoot, cacheDir, cacheLocation) {
|
|
@@ -141821,18 +142786,18 @@ async function buildInspectReport(projectRoot, includeRoots, files, discovery, g
|
|
|
141821
142786
|
};
|
|
141822
142787
|
}
|
|
141823
142788
|
async function handleInspectCommand(context) {
|
|
141824
|
-
const commandStart =
|
|
142789
|
+
const commandStart = performance19.now();
|
|
141825
142790
|
const cache = parseCacheModeOption(context.getOpt("--cache"));
|
|
141826
142791
|
const limit = parsePositiveIntegerOption(context.getOpt("--limit"), "--limit", 20);
|
|
141827
|
-
const resolveStart =
|
|
142792
|
+
const resolveStart = performance19.now();
|
|
141828
142793
|
const files = await context.resolveFilesFromRoots();
|
|
141829
142794
|
if (context.commandReport) {
|
|
141830
|
-
context.commandReport.timings.resolveFilesMs = Math.round(
|
|
142795
|
+
context.commandReport.timings.resolveFilesMs = Math.round(performance19.now() - resolveStart);
|
|
141831
142796
|
}
|
|
141832
142797
|
const report2 = await buildInspectReport(context.projectRootFs, context.includeRootsAbs, files, context.discoveryOptions, context.graphOptions, context.languageExtensions, cache, context.getOpt("--cache-dir"), context.cacheLocation, context.workerOpts, context.progressHandler, context.commandReport?.index, limit, context.hasFlag("--duplicates"), context.writeStderrLine);
|
|
141833
142798
|
writeCliOutput(context, report2, formatInspectReport);
|
|
141834
142799
|
if (context.commandReport && context.writeCommandReport) {
|
|
141835
|
-
context.commandReport.timings.commandMs = Math.round(
|
|
142800
|
+
context.commandReport.timings.commandMs = Math.round(performance19.now() - commandStart);
|
|
141836
142801
|
context.commandReport.timings.totalMs = context.commandReport.timings.commandMs;
|
|
141837
142802
|
await context.writeCommandReport(context.commandReport, context.reportFile);
|
|
141838
142803
|
}
|
|
@@ -141886,6 +142851,7 @@ var init_inspect = __esm({
|
|
|
141886
142851
|
});
|
|
141887
142852
|
|
|
141888
142853
|
// dist/cli/command-table.js
|
|
142854
|
+
import { performance as performance20 } from "node:perf_hooks";
|
|
141889
142855
|
function agentIo(ctx) {
|
|
141890
142856
|
return {
|
|
141891
142857
|
positionals: ctx.parsed.positionals,
|
|
@@ -142358,6 +143324,7 @@ var init_command_table = __esm({
|
|
|
142358
143324
|
duplicates: {
|
|
142359
143325
|
stage: "project",
|
|
142360
143326
|
run: async (ctx) => {
|
|
143327
|
+
const startedAt = performance20.now();
|
|
142361
143328
|
const files = await ctx.resolveFiles();
|
|
142362
143329
|
const { handleDuplicatesCommand: handleDuplicatesCommand2 } = await Promise.resolve().then(() => (init_duplicates2(), duplicates_exports));
|
|
142363
143330
|
await handleDuplicatesCommand2({
|
|
@@ -142366,6 +143333,8 @@ var init_command_table = __esm({
|
|
|
142366
143333
|
getOpt: ctx.getOpt,
|
|
142367
143334
|
hasFlag: ctx.hasFlag,
|
|
142368
143335
|
loadCurrentIndex: ctx.createDuplicateIndexLoader(),
|
|
143336
|
+
progressHandler: ctx.progressHandler,
|
|
143337
|
+
progressStartedAt: startedAt,
|
|
142369
143338
|
writeJSONLine,
|
|
142370
143339
|
writeStdoutLine,
|
|
142371
143340
|
writeStderrLine,
|
|
@@ -143481,7 +144450,7 @@ function openViewerUrl(url2) {
|
|
|
143481
144450
|
command = "xdg-open";
|
|
143482
144451
|
args = [url2];
|
|
143483
144452
|
}
|
|
143484
|
-
const child = spawn5(command, args, { detached: true, stdio: "ignore" });
|
|
144453
|
+
const child = spawn5(command, args, { windowsHide: true, detached: true, stdio: "ignore" });
|
|
143485
144454
|
child.once("error", () => {
|
|
143486
144455
|
});
|
|
143487
144456
|
child.unref();
|