codeql-development-mcp-server 2.25.2-rc1 → 2.25.3

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.
@@ -3600,49 +3600,49 @@ var require_fast_uri = __commonJS({
3600
3600
  schemelessOptions.skipEscape = true;
3601
3601
  return serialize(resolved, schemelessOptions);
3602
3602
  }
3603
- function resolveComponent(base, relative3, options, skipNormalization) {
3603
+ function resolveComponent(base, relative4, options, skipNormalization) {
3604
3604
  const target = {};
3605
3605
  if (!skipNormalization) {
3606
3606
  base = parse4(serialize(base, options), options);
3607
- relative3 = parse4(serialize(relative3, options), options);
3607
+ relative4 = parse4(serialize(relative4, options), options);
3608
3608
  }
3609
3609
  options = options || {};
3610
- if (!options.tolerant && relative3.scheme) {
3611
- target.scheme = relative3.scheme;
3612
- target.userinfo = relative3.userinfo;
3613
- target.host = relative3.host;
3614
- target.port = relative3.port;
3615
- target.path = removeDotSegments(relative3.path || "");
3616
- target.query = relative3.query;
3610
+ if (!options.tolerant && relative4.scheme) {
3611
+ target.scheme = relative4.scheme;
3612
+ target.userinfo = relative4.userinfo;
3613
+ target.host = relative4.host;
3614
+ target.port = relative4.port;
3615
+ target.path = removeDotSegments(relative4.path || "");
3616
+ target.query = relative4.query;
3617
3617
  } else {
3618
- if (relative3.userinfo !== void 0 || relative3.host !== void 0 || relative3.port !== void 0) {
3619
- target.userinfo = relative3.userinfo;
3620
- target.host = relative3.host;
3621
- target.port = relative3.port;
3622
- target.path = removeDotSegments(relative3.path || "");
3623
- target.query = relative3.query;
3618
+ if (relative4.userinfo !== void 0 || relative4.host !== void 0 || relative4.port !== void 0) {
3619
+ target.userinfo = relative4.userinfo;
3620
+ target.host = relative4.host;
3621
+ target.port = relative4.port;
3622
+ target.path = removeDotSegments(relative4.path || "");
3623
+ target.query = relative4.query;
3624
3624
  } else {
3625
- if (!relative3.path) {
3625
+ if (!relative4.path) {
3626
3626
  target.path = base.path;
3627
- if (relative3.query !== void 0) {
3628
- target.query = relative3.query;
3627
+ if (relative4.query !== void 0) {
3628
+ target.query = relative4.query;
3629
3629
  } else {
3630
3630
  target.query = base.query;
3631
3631
  }
3632
3632
  } else {
3633
- if (relative3.path[0] === "/") {
3634
- target.path = removeDotSegments(relative3.path);
3633
+ if (relative4.path[0] === "/") {
3634
+ target.path = removeDotSegments(relative4.path);
3635
3635
  } else {
3636
3636
  if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
3637
- target.path = "/" + relative3.path;
3637
+ target.path = "/" + relative4.path;
3638
3638
  } else if (!base.path) {
3639
- target.path = relative3.path;
3639
+ target.path = relative4.path;
3640
3640
  } else {
3641
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative3.path;
3641
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative4.path;
3642
3642
  }
3643
3643
  target.path = removeDotSegments(target.path);
3644
3644
  }
3645
- target.query = relative3.query;
3645
+ target.query = relative4.query;
3646
3646
  }
3647
3647
  target.userinfo = base.userinfo;
3648
3648
  target.host = base.host;
@@ -3650,7 +3650,7 @@ var require_fast_uri = __commonJS({
3650
3650
  }
3651
3651
  target.scheme = base.scheme;
3652
3652
  }
3653
- target.fragment = relative3.fragment;
3653
+ target.fragment = relative4.fragment;
3654
3654
  return target;
3655
3655
  }
3656
3656
  function equal(uriA, uriB, options) {
@@ -13305,7 +13305,7 @@ var require_src = __commonJS({
13305
13305
  // ../node_modules/depd/index.js
13306
13306
  var require_depd = __commonJS({
13307
13307
  "../node_modules/depd/index.js"(exports, module) {
13308
- var relative3 = __require("path").relative;
13308
+ var relative4 = __require("path").relative;
13309
13309
  module.exports = depd;
13310
13310
  var basePath = process.cwd();
13311
13311
  function containsNamespace(str2, namespace) {
@@ -13497,7 +13497,7 @@ var require_depd = __commonJS({
13497
13497
  return formatted;
13498
13498
  }
13499
13499
  function formatLocation(callSite) {
13500
- return relative3(basePath, callSite[0]) + ":" + callSite[1] + ":" + callSite[2];
13500
+ return relative4(basePath, callSite[0]) + ":" + callSite[1] + ":" + callSite[2];
13501
13501
  }
13502
13502
  function getStack() {
13503
13503
  var limit = Error.stackTraceLimit;
@@ -32676,9 +32676,8 @@ var require_side_channel_list = __commonJS({
32676
32676
  }
32677
32677
  },
32678
32678
  "delete": function(key) {
32679
- var root = $o && $o.next;
32680
32679
  var deletedNode = listDelete($o, key);
32681
- if (deletedNode && root && root === deletedNode) {
32680
+ if (deletedNode && $o && !$o.next) {
32682
32681
  $o = void 0;
32683
32682
  }
32684
32683
  return !!deletedNode;
@@ -34321,9 +34320,9 @@ var require_parse = __commonJS({
34321
34320
  var limit = options.parameterLimit === Infinity ? void 0 : options.parameterLimit;
34322
34321
  var parts = cleanStr.split(
34323
34322
  options.delimiter,
34324
- options.throwOnLimitExceeded ? limit + 1 : limit
34323
+ options.throwOnLimitExceeded && typeof limit !== "undefined" ? limit + 1 : limit
34325
34324
  );
34326
- if (options.throwOnLimitExceeded && parts.length > limit) {
34325
+ if (options.throwOnLimitExceeded && typeof limit !== "undefined" && parts.length > limit) {
34327
34326
  throw new RangeError("Parameter limit exceeded. Only " + limit + " parameter" + (limit === 1 ? "" : "s") + " allowed.");
34328
34327
  }
34329
34328
  var skipIndex = -1;
@@ -35004,7 +35003,7 @@ var require_view = __commonJS({
35004
35003
  var path3 = __require("node:path");
35005
35004
  var fs3 = __require("node:fs");
35006
35005
  var dirname10 = path3.dirname;
35007
- var basename10 = path3.basename;
35006
+ var basename11 = path3.basename;
35008
35007
  var extname3 = path3.extname;
35009
35008
  var join23 = path3.join;
35010
35009
  var resolve15 = path3.resolve;
@@ -35043,7 +35042,7 @@ var require_view = __commonJS({
35043
35042
  var root = roots[i];
35044
35043
  var loc = resolve15(root, name);
35045
35044
  var dir = dirname10(loc);
35046
- var file = basename10(loc);
35045
+ var file = basename11(loc);
35047
35046
  path4 = this.resolve(dir, file);
35048
35047
  }
35049
35048
  return path4;
@@ -35073,7 +35072,7 @@ var require_view = __commonJS({
35073
35072
  if (stat && stat.isFile()) {
35074
35073
  return path4;
35075
35074
  }
35076
- path4 = join23(dir, basename10(file, ext), "index" + ext);
35075
+ path4 = join23(dir, basename11(file, ext), "index" + ext);
35077
35076
  stat = tryStat(path4);
35078
35077
  if (stat && stat.isFile()) {
35079
35078
  return path4;
@@ -38371,10 +38370,8 @@ var require_content_disposition = __commonJS({
38371
38370
  "use strict";
38372
38371
  module.exports = contentDisposition;
38373
38372
  module.exports.parse = parse4;
38374
- var basename10 = __require("path").basename;
38373
+ var utf8Decoder = new TextDecoder("utf-8");
38375
38374
  var ENCODE_URL_ATTR_CHAR_REGEXP = /[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g;
38376
- var HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/;
38377
- var HEX_ESCAPE_REPLACE_REGEXP = /%([0-9A-Fa-f]{2})/g;
38378
38375
  var NON_LATIN1_REGEXP = /[^\x20-\x7e\xa0-\xff]/g;
38379
38376
  var QESC_REGEXP = /\\([\u0000-\u007f])/g;
38380
38377
  var QUOTE_REGEXP = /([\\"])/g;
@@ -38406,11 +38403,11 @@ var require_content_disposition = __commonJS({
38406
38403
  if (typeof fallback === "string" && NON_LATIN1_REGEXP.test(fallback)) {
38407
38404
  throw new TypeError("fallback must be ISO-8859-1 string");
38408
38405
  }
38409
- var name = basename10(filename);
38406
+ var name = basename11(filename);
38410
38407
  var isQuotedString = TEXT_REGEXP.test(name);
38411
- var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) : basename10(fallback);
38408
+ var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) : basename11(fallback);
38412
38409
  var hasFallback = typeof fallbackName === "string" && fallbackName !== name;
38413
- if (hasFallback || !isQuotedString || HEX_ESCAPE_REGEXP.test(name)) {
38410
+ if (hasFallback || !isQuotedString || hasHexEscape(name)) {
38414
38411
  params["filename*"] = name;
38415
38412
  }
38416
38413
  if (isQuotedString || hasFallback) {
@@ -38437,26 +38434,32 @@ var require_content_disposition = __commonJS({
38437
38434
  return string3;
38438
38435
  }
38439
38436
  function decodefield(str2) {
38440
- var match = EXT_VALUE_REGEXP.exec(str2);
38437
+ const match = EXT_VALUE_REGEXP.exec(str2);
38441
38438
  if (!match) {
38442
38439
  throw new TypeError("invalid extended field value");
38443
38440
  }
38444
- var charset = match[1].toLowerCase();
38445
- var encoded = match[2];
38446
- var value;
38447
- var binary2 = encoded.replace(HEX_ESCAPE_REPLACE_REGEXP, pdecode);
38441
+ const charset = match[1].toLowerCase();
38442
+ const encoded = match[2];
38448
38443
  switch (charset) {
38449
- case "iso-8859-1":
38450
- value = getlatin1(binary2);
38451
- break;
38444
+ case "iso-8859-1": {
38445
+ const binary2 = decodeHexEscapes(encoded);
38446
+ return getlatin1(binary2);
38447
+ }
38452
38448
  case "utf-8":
38453
- case "utf8":
38454
- value = Buffer.from(binary2, "binary").toString("utf8");
38455
- break;
38456
- default:
38457
- throw new TypeError("unsupported charset in extended field");
38449
+ case "utf8": {
38450
+ try {
38451
+ return decodeURIComponent(encoded);
38452
+ } catch {
38453
+ const binary2 = decodeHexEscapes(encoded);
38454
+ const bytes = new Uint8Array(binary2.length);
38455
+ for (let idx = 0; idx < binary2.length; idx++) {
38456
+ bytes[idx] = binary2.charCodeAt(idx);
38457
+ }
38458
+ return utf8Decoder.decode(bytes);
38459
+ }
38460
+ }
38458
38461
  }
38459
- return value;
38462
+ throw new TypeError("unsupported charset in extended field");
38460
38463
  }
38461
38464
  function getlatin1(val) {
38462
38465
  return String(val).replace(NON_LATIN1_REGEXP, "?");
@@ -38506,9 +38509,6 @@ var require_content_disposition = __commonJS({
38506
38509
  }
38507
38510
  return new ContentDisposition(type2, params);
38508
38511
  }
38509
- function pdecode(str2, hex) {
38510
- return String.fromCharCode(parseInt(hex, 16));
38511
- }
38512
38512
  function pencode(char) {
38513
38513
  return "%" + String(char).charCodeAt(0).toString(16).toUpperCase();
38514
38514
  }
@@ -38525,6 +38525,51 @@ var require_content_disposition = __commonJS({
38525
38525
  this.type = type2;
38526
38526
  this.parameters = parameters;
38527
38527
  }
38528
+ function basename11(path3) {
38529
+ const normalized = path3.replaceAll("\\", "/");
38530
+ let end = normalized.length;
38531
+ while (end > 0 && normalized[end - 1] === "/") {
38532
+ end--;
38533
+ }
38534
+ if (end === 0) {
38535
+ return "";
38536
+ }
38537
+ let start = end - 1;
38538
+ while (start >= 0 && normalized[start] !== "/") {
38539
+ start--;
38540
+ }
38541
+ return normalized.slice(start + 1, end);
38542
+ }
38543
+ function isHexDigit(char) {
38544
+ const code = char.charCodeAt(0);
38545
+ return code >= 48 && code <= 57 || // 0-9
38546
+ code >= 65 && code <= 70 || // A-F
38547
+ code >= 97 && code <= 102;
38548
+ }
38549
+ function hasHexEscape(str2) {
38550
+ const maxIndex = str2.length - 3;
38551
+ let lastIndex = -1;
38552
+ while ((lastIndex = str2.indexOf("%", lastIndex + 1)) !== -1 && lastIndex <= maxIndex) {
38553
+ if (isHexDigit(str2[lastIndex + 1]) && isHexDigit(str2[lastIndex + 2])) {
38554
+ return true;
38555
+ }
38556
+ }
38557
+ return false;
38558
+ }
38559
+ function decodeHexEscapes(str2) {
38560
+ const firstEscape = str2.indexOf("%");
38561
+ if (firstEscape === -1) return str2;
38562
+ let result = str2.slice(0, firstEscape);
38563
+ for (let idx = firstEscape; idx < str2.length; idx++) {
38564
+ if (str2[idx] === "%" && idx + 2 < str2.length && isHexDigit(str2[idx + 1]) && isHexDigit(str2[idx + 2])) {
38565
+ result += String.fromCharCode(Number.parseInt(str2[idx + 1] + str2[idx + 2], 16));
38566
+ idx += 2;
38567
+ } else {
38568
+ result += str2[idx];
38569
+ }
38570
+ }
38571
+ return result;
38572
+ }
38528
38573
  }
38529
38574
  });
38530
38575
 
@@ -38735,7 +38780,7 @@ var require_send = __commonJS({
38735
38780
  var join23 = path3.join;
38736
38781
  var normalize2 = path3.normalize;
38737
38782
  var resolve15 = path3.resolve;
38738
- var sep4 = path3.sep;
38783
+ var sep5 = path3.sep;
38739
38784
  var BYTES_RANGE_REGEXP = /^ *bytes=/;
38740
38785
  var MAX_MAXAGE = 60 * 60 * 24 * 365 * 1e3;
38741
38786
  var UP_PATH_REGEXP = /(?:^|[\\/])\.\.(?:[\\/]|$)/;
@@ -38896,14 +38941,14 @@ var require_send = __commonJS({
38896
38941
  var parts;
38897
38942
  if (root !== null) {
38898
38943
  if (path4) {
38899
- path4 = normalize2("." + sep4 + path4);
38944
+ path4 = normalize2("." + sep5 + path4);
38900
38945
  }
38901
38946
  if (UP_PATH_REGEXP.test(path4)) {
38902
38947
  debug('malicious path "%s"', path4);
38903
38948
  this.error(403);
38904
38949
  return res;
38905
38950
  }
38906
- parts = path4.split(sep4);
38951
+ parts = path4.split(sep5);
38907
38952
  path4 = normalize2(join23(root, path4));
38908
38953
  } else {
38909
38954
  if (UP_PATH_REGEXP.test(path4)) {
@@ -38911,7 +38956,7 @@ var require_send = __commonJS({
38911
38956
  this.error(403);
38912
38957
  return res;
38913
38958
  }
38914
- parts = normalize2(path4).split(sep4);
38959
+ parts = normalize2(path4).split(sep5);
38915
38960
  path4 = resolve15(path4);
38916
38961
  }
38917
38962
  if (containsDotFile(parts)) {
@@ -39005,7 +39050,7 @@ var require_send = __commonJS({
39005
39050
  var self2 = this;
39006
39051
  debug('stat "%s"', path4);
39007
39052
  fs3.stat(path4, function onstat(err, stat) {
39008
- var pathEndsWithSep = path4[path4.length - 1] === sep4;
39053
+ var pathEndsWithSep = path4[path4.length - 1] === sep5;
39009
39054
  if (err && err.code === "ENOENT" && !extname3(path4) && !pathEndsWithSep) {
39010
39055
  return next(err);
39011
39056
  }
@@ -40383,8 +40428,8 @@ var require_main = __commonJS({
40383
40428
  const shortPaths = [];
40384
40429
  for (const filePath of optionPaths) {
40385
40430
  try {
40386
- const relative3 = path3.relative(process.cwd(), filePath);
40387
- shortPaths.push(relative3);
40431
+ const relative4 = path3.relative(process.cwd(), filePath);
40432
+ shortPaths.push(relative4);
40388
40433
  } catch (e) {
40389
40434
  if (debug) {
40390
40435
  _debug(`failed to load ${filePath} ${e.message}`);
@@ -40392,7 +40437,7 @@ var require_main = __commonJS({
40392
40437
  lastError = e;
40393
40438
  }
40394
40439
  }
40395
- _log(`injecting env (${keysCount}) from ${shortPaths.join(",")} ${dim(`// tip: ${_getRandomTip()}`)}`);
40440
+ _log(`injected env (${keysCount}) from ${shortPaths.join(",")} ${dim(`// tip: ${_getRandomTip()}`)}`);
40396
40441
  }
40397
40442
  if (lastError) {
40398
40443
  return { parsed: parsedAll, error: lastError };
@@ -172214,8 +172259,8 @@ var require_adm_zip = __commonJS({
172214
172259
  return null;
172215
172260
  }
172216
172261
  function fixPath(zipPath) {
172217
- const { join: join23, normalize: normalize2, sep: sep4 } = pth.posix;
172218
- return join23(pth.isAbsolute(zipPath) ? "/" : ".", normalize2(sep4 + zipPath.split("\\").join(sep4) + sep4));
172262
+ const { join: join23, normalize: normalize2, sep: sep5 } = pth.posix;
172263
+ return join23(pth.isAbsolute(zipPath) ? "/" : ".", normalize2(sep5 + zipPath.split("\\").join(sep5) + sep5));
172219
172264
  }
172220
172265
  function filenameFilter(filterfn) {
172221
172266
  if (filterfn instanceof RegExp) {
@@ -188585,12 +188630,13 @@ init_logger();
188585
188630
  // src/lib/log-directory-manager.ts
188586
188631
  init_temp_dir();
188587
188632
  import { mkdirSync as mkdirSync3, existsSync as existsSync5 } from "fs";
188588
- import { join as join7, resolve as resolve3 } from "path";
188633
+ import { join as join7, resolve as resolve3, sep, relative, isAbsolute as isAbsolute3 } from "path";
188589
188634
  import { randomBytes } from "crypto";
188590
188635
  function ensurePathWithinBase(baseDir, targetPath) {
188591
188636
  const absBase = resolve3(baseDir);
188592
188637
  const absTarget = resolve3(targetPath);
188593
- if (!absTarget.startsWith(absBase + "/") && absTarget !== absBase) {
188638
+ const rel = relative(absBase, absTarget);
188639
+ if (rel === ".." || rel.startsWith(".." + sep) || isAbsolute3(rel)) {
188594
188640
  throw new Error(`Provided log directory is outside the allowed base directory: ${absBase}`);
188595
188641
  }
188596
188642
  return absTarget;
@@ -188726,7 +188772,7 @@ import { createHash as createHash2 } from "crypto";
188726
188772
  init_cli_executor();
188727
188773
  init_logger();
188728
188774
  import { closeSync, fstatSync, mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync5, writeFileSync } from "fs";
188729
- import { dirname as dirname3, isAbsolute as isAbsolute3 } from "path";
188775
+ import { dirname as dirname3, isAbsolute as isAbsolute4 } from "path";
188730
188776
  var BUILT_IN_EVALUATORS = {
188731
188777
  "json-decode": "JSON format decoder for query results",
188732
188778
  "csv-decode": "CSV format decoder for query results",
@@ -188979,7 +189025,7 @@ async function evaluateQueryResults(bqrsPath, queryPath, evaluationFunction, out
188979
189025
  case "mermaid-graph":
188980
189026
  return await evaluateWithMermaidGraph(bqrsPath, queryPath, outputPath);
188981
189027
  default:
188982
- if (isAbsolute3(evalFunc)) {
189028
+ if (isAbsolute4(evalFunc)) {
188983
189029
  return await evaluateWithCustomScript(bqrsPath, queryPath, evalFunc, outputPath);
188984
189030
  } else {
188985
189031
  return {
@@ -189396,10 +189442,43 @@ function diffSarifRules(sarifA, sarifB) {
189396
189442
  unchangedRules
189397
189443
  };
189398
189444
  }
189445
+ function computeFingerprintOverlap(resultA, resultB) {
189446
+ const fpA = resultA.partialFingerprints;
189447
+ const fpB = resultB.partialFingerprints;
189448
+ if (!fpA || !fpB || Object.keys(fpA).length === 0 || Object.keys(fpB).length === 0) {
189449
+ return {
189450
+ fingerprintMatch: false,
189451
+ overlaps: false,
189452
+ overlapMode: "fingerprint",
189453
+ sharedLocations: []
189454
+ };
189455
+ }
189456
+ const matchedFingerprints = {};
189457
+ for (const key of Object.keys(fpA)) {
189458
+ if (key in fpB && fpA[key] === fpB[key]) {
189459
+ matchedFingerprints[key] = fpA[key];
189460
+ }
189461
+ }
189462
+ const hasMatch = Object.keys(matchedFingerprints).length > 0;
189463
+ return {
189464
+ fingerprintMatch: hasMatch,
189465
+ matchedFingerprints: hasMatch ? matchedFingerprints : void 0,
189466
+ overlaps: hasMatch,
189467
+ overlapMode: "fingerprint",
189468
+ sharedLocations: []
189469
+ };
189470
+ }
189399
189471
  function computeLocationOverlap(resultA, resultB, mode = "sink") {
189400
189472
  let locsA;
189401
189473
  let locsB;
189402
189474
  switch (mode) {
189475
+ case "fingerprint": {
189476
+ const fpResult = computeFingerprintOverlap(resultA, resultB);
189477
+ if (fpResult.fingerprintMatch) {
189478
+ return fpResult;
189479
+ }
189480
+ return computeLocationOverlap(resultA, resultB, "full-path");
189481
+ }
189403
189482
  case "sink":
189404
189483
  locsA = extractPrimaryLocations(resultA);
189405
189484
  locsB = extractPrimaryLocations(resultB);
@@ -189439,6 +189518,99 @@ function computeLocationOverlap(resultA, resultB, mode = "sink") {
189439
189518
  sharedLocations: shared
189440
189519
  };
189441
189520
  }
189521
+ function findOverlappingAlerts(resultsA, ruleA, resultsB, ruleB, mode = "sink") {
189522
+ const overlaps = [];
189523
+ for (let i = 0; i < resultsA.length; i++) {
189524
+ for (let j = 0; j < resultsB.length; j++) {
189525
+ const overlapDetails = computeLocationOverlap(resultsA[i], resultsB[j], mode);
189526
+ if (overlapDetails.overlaps) {
189527
+ overlaps.push({
189528
+ overlapDetails,
189529
+ resultA: resultsA[i],
189530
+ resultAIndex: i,
189531
+ resultB: resultsB[j],
189532
+ resultBIndex: j,
189533
+ ruleIdA: ruleA.id,
189534
+ ruleIdB: ruleB.id
189535
+ });
189536
+ }
189537
+ }
189538
+ }
189539
+ return overlaps;
189540
+ }
189541
+ function lineInHunks(line, hunks) {
189542
+ for (const hunk of hunks) {
189543
+ const hunkEnd = hunk.startLine + Math.max(hunk.lineCount - 1, 0);
189544
+ if (line >= hunk.startLine && line <= hunkEnd) {
189545
+ return true;
189546
+ }
189547
+ }
189548
+ return false;
189549
+ }
189550
+ function diffSarifByCommits(sarif, diffFiles, refRange, granularity = "file") {
189551
+ const results = sarif.runs[0]?.results ?? [];
189552
+ const newResults = [];
189553
+ const preExistingResults = [];
189554
+ const normalizedDiffEntries = diffFiles.map((df) => ({
189555
+ entry: df,
189556
+ normalized: normalizeUri(df.path)
189557
+ }));
189558
+ for (let i = 0; i < results.length; i++) {
189559
+ const result = results[i];
189560
+ const primaryLoc = result.locations?.[0]?.physicalLocation;
189561
+ const uri = primaryLoc?.artifactLocation?.uri;
189562
+ if (!uri) {
189563
+ preExistingResults.push({
189564
+ file: "<unknown>",
189565
+ resultIndex: i,
189566
+ ruleId: result.ruleId
189567
+ });
189568
+ continue;
189569
+ }
189570
+ const startLine = primaryLoc?.region?.startLine;
189571
+ const normalizedUri = normalizeUri(uri);
189572
+ let matchingDiff;
189573
+ for (const { entry, normalized } of normalizedDiffEntries) {
189574
+ if (normalized === normalizedUri || normalized.endsWith(normalizedUri) || normalizedUri.endsWith(normalized)) {
189575
+ matchingDiff = entry;
189576
+ break;
189577
+ }
189578
+ }
189579
+ let isNew = false;
189580
+ if (matchingDiff) {
189581
+ if (granularity === "file") {
189582
+ isNew = true;
189583
+ } else if (startLine !== void 0 && matchingDiff.hunks.length > 0) {
189584
+ isNew = lineInHunks(startLine, matchingDiff.hunks);
189585
+ } else if (matchingDiff.hunks.length === 0 && !matchingDiff.hunksParsed) {
189586
+ isNew = true;
189587
+ }
189588
+ }
189589
+ const classified = {
189590
+ file: matchingDiff ? matchingDiff.path : normalizedUri,
189591
+ line: startLine,
189592
+ resultIndex: i,
189593
+ ruleId: result.ruleId
189594
+ };
189595
+ if (isNew) {
189596
+ newResults.push(classified);
189597
+ } else {
189598
+ preExistingResults.push(classified);
189599
+ }
189600
+ }
189601
+ return {
189602
+ granularity,
189603
+ newResults,
189604
+ preExistingResults,
189605
+ summary: {
189606
+ diffFileCount: diffFiles.length,
189607
+ refRange,
189608
+ totalNew: newResults.length,
189609
+ totalPreExisting: preExistingResults.length,
189610
+ totalResults: results.length
189611
+ }
189612
+ };
189613
+ }
189442
189614
 
189443
189615
  // src/lib/session-data-manager.ts
189444
189616
  init_temp_dir();
@@ -190314,8 +190486,8 @@ var MonitoringConfigSchema = external_exports.object({
190314
190486
  enableRecommendations: external_exports.boolean().default(true),
190315
190487
  enableMonitoringTools: external_exports.boolean().default(false),
190316
190488
  // Opt-in: session_* tools disabled by default for end-users
190317
- enableAnnotationTools: external_exports.boolean().default(false)
190318
- // Opt-in: annotation_* and audit_* tools disabled by default
190489
+ enableAnnotationTools: external_exports.boolean().default(true)
190490
+ // Controls auto-caching behaviour in result-processor; tools are always registered
190319
190491
  });
190320
190492
 
190321
190493
  // src/lib/session-data-manager.ts
@@ -190602,7 +190774,7 @@ function parseBoolEnv(envVar, defaultValue) {
190602
190774
  var sessionDataManager = new SessionDataManager({
190603
190775
  storageLocation: process.env.MONITORING_STORAGE_LOCATION || join9(getProjectTmpBase(), ".ql-mcp-tracking"),
190604
190776
  enableMonitoringTools: parseBoolEnv(process.env.ENABLE_MONITORING_TOOLS, false),
190605
- enableAnnotationTools: parseBoolEnv(process.env.ENABLE_ANNOTATION_TOOLS, false)
190777
+ enableAnnotationTools: parseBoolEnv(process.env.ENABLE_ANNOTATION_TOOLS, true)
190606
190778
  });
190607
190779
 
190608
190780
  // src/lib/result-processor.ts
@@ -190932,7 +191104,7 @@ function cacheDatabaseAnalyzeResults(params, logger2) {
190932
191104
  // src/lib/cli-tool-registry.ts
190933
191105
  init_package_paths();
190934
191106
  import { existsSync as existsSync6, mkdirSync as mkdirSync8, realpathSync, rmSync, writeFileSync as writeFileSync4 } from "fs";
190935
- import { delimiter as delimiter5, dirname as dirname5, isAbsolute as isAbsolute4, join as join10, resolve as resolve4 } from "path";
191107
+ import { basename as basename5, delimiter as delimiter5, dirname as dirname5, isAbsolute as isAbsolute5, join as join10, resolve as resolve4 } from "path";
190936
191108
 
190937
191109
  // ../node_modules/js-yaml/dist/js-yaml.mjs
190938
191110
  function isNothing(subject) {
@@ -193711,12 +193883,12 @@ function registerCLITool(server, definition) {
193711
193883
  if (tests && Array.isArray(tests)) {
193712
193884
  const userDir = getUserWorkspaceDir();
193713
193885
  positionalArgs = [...positionalArgs, ...tests.map(
193714
- (t) => isAbsolute4(t) ? t : resolve4(userDir, t)
193886
+ (t) => isAbsolute5(t) ? t : resolve4(userDir, t)
193715
193887
  )];
193716
193888
  }
193717
193889
  break;
193718
193890
  case "codeql_query_run": {
193719
- if (options.database && typeof options.database === "string" && !isAbsolute4(options.database)) {
193891
+ if (options.database && typeof options.database === "string" && !isAbsolute5(options.database)) {
193720
193892
  options.database = resolve4(getUserWorkspaceDir(), options.database);
193721
193893
  logger.info(`Resolved database path to: ${options.database}`);
193722
193894
  }
@@ -193836,6 +194008,19 @@ function registerCLITool(server, definition) {
193836
194008
  break;
193837
194009
  }
193838
194010
  case "codeql_query_compile":
194011
+ if (query) {
194012
+ positionalArgs = [...positionalArgs, query];
194013
+ }
194014
+ if (options["dump-dil"] === void 0) {
194015
+ const pending = Array.isArray(options.additionalArgs) ? options.additionalArgs : [];
194016
+ const hasDilOverride = pending.some(
194017
+ (arg) => arg === "--no-dump-dil" || arg === "--dump-dil"
194018
+ );
194019
+ if (!hasDilOverride) {
194020
+ options["dump-dil"] = true;
194021
+ }
194022
+ }
194023
+ break;
193839
194024
  case "codeql_resolve_metadata":
193840
194025
  if (query) {
193841
194026
  positionalArgs = [...positionalArgs, query];
@@ -193885,8 +194070,25 @@ function registerCLITool(server, definition) {
193885
194070
  mkdirSync8(outputDir, { recursive: true });
193886
194071
  }
193887
194072
  }
193888
- const rawAdditionalArgs = Array.isArray(options.additionalArgs) ? options.additionalArgs : [];
194073
+ let effectiveDumpDilEnabled = false;
194074
+ let rawAdditionalArgs = Array.isArray(options.additionalArgs) ? options.additionalArgs : [];
193889
194075
  delete options.additionalArgs;
194076
+ if (name === "codeql_query_compile") {
194077
+ const lastDumpDilFlag = [...rawAdditionalArgs].reverse().find(
194078
+ (arg) => arg === "--dump-dil" || arg === "--no-dump-dil"
194079
+ );
194080
+ if (lastDumpDilFlag === "--dump-dil") {
194081
+ options["dump-dil"] = true;
194082
+ } else if (lastDumpDilFlag === "--no-dump-dil") {
194083
+ options["dump-dil"] = false;
194084
+ }
194085
+ if (lastDumpDilFlag !== void 0) {
194086
+ rawAdditionalArgs = rawAdditionalArgs.filter(
194087
+ (arg) => arg !== "--dump-dil" && arg !== "--no-dump-dil"
194088
+ );
194089
+ }
194090
+ effectiveDumpDilEnabled = options["dump-dil"] !== false;
194091
+ }
193890
194092
  const managedFlagNames = /* @__PURE__ */ new Set([
193891
194093
  "evaluator-log",
193892
194094
  "logdir",
@@ -193918,7 +194120,7 @@ function registerCLITool(server, definition) {
193918
194120
  let cwd;
193919
194121
  if ((name === "codeql_pack_install" || name === "codeql_pack_ls") && (dir || packDir)) {
193920
194122
  const rawCwd = dir || packDir;
193921
- cwd = isAbsolute4(rawCwd) ? rawCwd : resolve4(getUserWorkspaceDir(), rawCwd);
194123
+ cwd = isAbsolute5(rawCwd) ? rawCwd : resolve4(getUserWorkspaceDir(), rawCwd);
193922
194124
  }
193923
194125
  const defaultExamplesPath = resolve4(packageRootDir, "ql", "javascript", "examples");
193924
194126
  const additionalPacksPath = process.env.CODEQL_ADDITIONAL_PACKS || (existsSync6(defaultExamplesPath) ? defaultExamplesPath : void 0);
@@ -193980,7 +194182,36 @@ function registerCLITool(server, definition) {
193980
194182
  const resolvedDb = typeof params.database === "string" ? resolveDatabasePath(params.database) : params.database;
193981
194183
  cacheDatabaseAnalyzeResults({ ...params, database: resolvedDb, output: options.output, format: options.format }, logger);
193982
194184
  }
193983
- const processedResult = resultProcessor(result, params);
194185
+ let dilFilePath;
194186
+ if (name === "codeql_query_compile" && result.success && effectiveDumpDilEnabled && result.stdout) {
194187
+ try {
194188
+ const compileLogDir = getOrCreateLogDirectory(customLogDir);
194189
+ logger.info(`Using log directory for ${name}: ${compileLogDir}`);
194190
+ const queryBaseName = query ? basename5(query, ".ql") : "query";
194191
+ dilFilePath = join10(compileLogDir, `${queryBaseName}.dil`);
194192
+ writeFileSync4(dilFilePath, result.stdout, "utf8");
194193
+ logger.info(`Saved DIL output to ${dilFilePath}`);
194194
+ } catch (dilError) {
194195
+ logger.warn(`Failed to save DIL output: ${dilError}`);
194196
+ dilFilePath = void 0;
194197
+ }
194198
+ }
194199
+ let processedResult;
194200
+ if (dilFilePath) {
194201
+ const stdoutBytes = Buffer.byteLength(result.stdout ?? "", "utf8");
194202
+ processedResult = `Compiled successfully. DIL output written to file (${stdoutBytes} bytes).`;
194203
+ if (result.stderr) {
194204
+ processedResult += `
194205
+
194206
+ Warnings/Info:
194207
+ ${result.stderr}`;
194208
+ }
194209
+ processedResult += `
194210
+
194211
+ DIL file: ${dilFilePath}`;
194212
+ } else {
194213
+ processedResult = resultProcessor(result, params);
194214
+ }
193984
194215
  return {
193985
194216
  content: [{
193986
194217
  type: "text",
@@ -195252,7 +195483,7 @@ var codeqlPackLsTool = {
195252
195483
 
195253
195484
  // src/tools/codeql/profile-codeql-query-from-logs.ts
195254
195485
  import { existsSync as existsSync11, mkdirSync as mkdirSync9, writeFileSync as writeFileSync5 } from "fs";
195255
- import { basename as basename6, dirname as dirname7, join as join15 } from "path";
195486
+ import { basename as basename7, dirname as dirname7, join as join15 } from "path";
195256
195487
 
195257
195488
  // src/lib/evaluator-log-parser.ts
195258
195489
  init_logger();
@@ -195584,7 +195815,7 @@ function buildDetailFile(profile, topN) {
195584
195815
  lines.push("");
195585
195816
  for (let qIdx = 0; qIdx < profile.queries.length; qIdx++) {
195586
195817
  const query = profile.queries[qIdx];
195587
- const qName = basename6(query.queryName);
195818
+ const qName = basename7(query.queryName);
195588
195819
  lines.push(`== Query: ${qName} ==`);
195589
195820
  lines.push(` Total: ${query.totalDurationMs.toFixed(2)}ms | Predicates evaluated: ${query.predicateCount} | Cache hits: ${query.cacheHits}`);
195590
195821
  lines.push("");
@@ -195743,7 +195974,7 @@ init_cli_executor();
195743
195974
  init_logger();
195744
195975
  import { writeFileSync as writeFileSync6, existsSync as existsSync12 } from "fs";
195745
195976
  import { createReadStream as createReadStream2 } from "fs";
195746
- import { join as join16, dirname as dirname8, basename as basename7 } from "path";
195977
+ import { join as join16, dirname as dirname8, basename as basename8 } from "path";
195747
195978
  import { mkdirSync as mkdirSync10 } from "fs";
195748
195979
  import { createInterface as createInterface2 } from "readline";
195749
195980
  async function parseEvaluatorLog2(logPath) {
@@ -195869,7 +196100,7 @@ function formatAsMermaid(profile) {
195869
196100
  lines.push("```mermaid");
195870
196101
  lines.push("graph TD");
195871
196102
  lines.push("");
195872
- lines.push(` QUERY["${basename7(profile.queryName)}<br/>Total: ${profile.totalDuration.toFixed(2)}ms"]`);
196103
+ lines.push(` QUERY["${basename8(profile.queryName)}<br/>Total: ${profile.totalDuration.toFixed(2)}ms"]`);
195873
196104
  lines.push("");
195874
196105
  profile.pipelines.forEach((pipeline) => {
195875
196106
  const nodeId = `P${pipeline.eventId}`;
@@ -196000,7 +196231,7 @@ function registerProfileCodeQLQueryTool(server) {
196000
196231
  ...outputFiles.map((f) => ` - ${f}`),
196001
196232
  "",
196002
196233
  "Profile Summary:",
196003
- ` - Query: ${basename7(profile.queryName)}`,
196234
+ ` - Query: ${basename8(profile.queryName)}`,
196004
196235
  ` - Total Duration: ${profile.totalDuration.toFixed(2)} ms`,
196005
196236
  ` - Total Pipelines: ${profile.pipelines.length}`,
196006
196237
  ` - Total Events: ${profile.totalEvents}`,
@@ -196037,13 +196268,15 @@ function registerProfileCodeQLQueryTool(server) {
196037
196268
  // src/tools/codeql/query-compile.ts
196038
196269
  var codeqlQueryCompileTool = {
196039
196270
  name: "codeql_query_compile",
196040
- description: "Compile and validate CodeQL queries",
196271
+ description: "Compile and validate CodeQL queries. By default, produces a .dil file containing the optimized DIL intermediate representation alongside the compilation output.",
196041
196272
  command: "codeql",
196042
196273
  subcommand: "query compile",
196043
196274
  inputSchema: {
196044
196275
  query: external_exports.string().describe("Path to the CodeQL query file (.ql)"),
196045
196276
  database: external_exports.string().optional().describe("Path to the CodeQL database"),
196277
+ "dump-dil": external_exports.boolean().optional().describe("Print the optimized DIL intermediate representation to standard output while compiling. Enabled by default; pass false or --no-dump-dil to disable."),
196046
196278
  library: external_exports.string().optional().describe("Path to query library"),
196279
+ logDir: external_exports.string().optional().describe("Custom directory for compilation DIL output (overrides CODEQL_QUERY_LOG_DIR environment variable). If not provided, uses CODEQL_QUERY_LOG_DIR or defaults to .tmp/query-logs/<unique-id>"),
196047
196280
  output: external_exports.string().optional().describe("Output file path"),
196048
196281
  warnings: external_exports.enum(["hide", "show", "error"]).optional().describe("How to handle compilation warnings"),
196049
196282
  verbose: external_exports.boolean().optional().describe("Enable verbose output"),
@@ -196051,6 +196284,7 @@ var codeqlQueryCompileTool = {
196051
196284
  },
196052
196285
  examples: [
196053
196286
  "codeql query compile --database=/path/to/db MyQuery.ql",
196287
+ "codeql query compile --dump-dil --database=/path/to/db MyQuery.ql",
196054
196288
  "codeql query compile --library=/path/to/lib --output=compiled.qlo MyQuery.ql"
196055
196289
  ]
196056
196290
  };
@@ -196699,7 +196933,7 @@ var codeqlResolveTestsTool = {
196699
196933
 
196700
196934
  // src/tools/codeql/search-ql-code.ts
196701
196935
  import { closeSync as closeSync2, createReadStream as createReadStream3, fstatSync as fstatSync2, lstatSync, openSync as openSync2, readdirSync as readdirSync8, readFileSync as readFileSync12, realpathSync as realpathSync2 } from "fs";
196702
- import { basename as basename8, extname as extname2, join as join19, resolve as resolve9 } from "path";
196936
+ import { basename as basename9, extname as extname2, join as join19, resolve as resolve9 } from "path";
196703
196937
  import { createInterface as createInterface3 } from "readline";
196704
196938
 
196705
196939
  // src/lib/scan-exclude.ts
@@ -196747,10 +196981,13 @@ var MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
196747
196981
  var MAX_FILES_TRAVERSED = 1e4;
196748
196982
  var MAX_CONTEXT_LINES = 50;
196749
196983
  var MAX_MAX_RESULTS = 1e4;
196750
- var SKIP_DIRS2 = getScanExcludeDirs();
196984
+ function getSkipDirs() {
196985
+ return getScanExcludeDirs();
196986
+ }
196751
196987
  function collectFiles(paths, extensions, fileCount) {
196752
196988
  const files = [];
196753
196989
  const visitedDirs = /* @__PURE__ */ new Set();
196990
+ const skipDirs = getSkipDirs();
196754
196991
  function walk(p) {
196755
196992
  if (fileCount.value >= MAX_FILES_TRAVERSED) return;
196756
196993
  let stat;
@@ -196766,7 +197003,7 @@ function collectFiles(paths, extensions, fileCount) {
196766
197003
  }
196767
197004
  fileCount.value++;
196768
197005
  } else if (stat.isDirectory()) {
196769
- if (SKIP_DIRS2.has(basename8(p))) return;
197006
+ if (skipDirs.has(basename9(p))) return;
196770
197007
  let realPath;
196771
197008
  try {
196772
197009
  realPath = realpathSync2(p);
@@ -197310,7 +197547,7 @@ var server_prompts_default = "# MCP Server Prompts\n\nThis resource provides a c
197310
197547
  var server_queries_default = '# MCP Server Bundled Queries\n\nThis resource describes the tools queries bundled with the CodeQL Development MCP Server. These queries run via `codeql_query_run` and provide structural insight into how source code is represented in a CodeQL database. Use them to understand code structure before writing detection queries.\n\nFor general QL query writing guidance (syntax, metadata, `from`/`where`/`select`, testing conventions), see `codeql://learning/query-basics`.\n\n## Bundled Tools Queries\n\nThe server bundles five tools queries that operate on CodeQL databases:\n\n| Query | Purpose | Output Format |\n| ----------------- | ------------------------------------------------------- | ------------------------- |\n| `PrintAST` | Visualize the Abstract Syntax Tree of source code | `@kind graph` (graphtext) |\n| `PrintCFG` | Visualize the Control Flow Graph of a function | `@kind graph` (graphtext) |\n| `CallGraphFrom` | Show all functions called FROM a given function | `@kind graph` (graphtext) |\n| `CallGraphTo` | Show all call sites that call TO a given function | `@kind graph` (graphtext) |\n| `CallGraphFromTo` | Show calls FROM one function TO another (bidirectional) | `@kind graph` (graphtext) |\n\nAll five queries use `@kind graph` metadata and produce output in graphtext format.\n\n## PrintAST\n\n**Purpose**: Outputs a hierarchical representation of the Abstract Syntax Tree showing parent-child relationships between declarations, statements, and expressions.\n\n**When to use**: Before writing any CodeQL query, run `PrintAST` on your test source code to understand which QL classes represent which source constructs and which predicates are available for matching.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "PrintAST"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFiles: "<comma-separated-filenames>" (optional \u2014 filter to specific files)\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A tree showing each AST node with its QL class name, properties, and position in the hierarchy. This reveals exactly which QL classes and predicates to use in `from`/`where`/`select` clauses.\n\n## PrintCFG\n\n**Purpose**: Produces a Control Flow Graph representation showing the order in which statements and expressions execute, including branching paths.\n\n**When to use**: When writing queries that reason about execution order, reachability, or branching logic (e.g., "is this check always performed before this call?").\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "PrintCFG"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFunction: "<function-name>" (optional \u2014 target a specific function)\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: Nodes representing CFG basic blocks and edges representing possible execution transitions (successor relationships).\n\n## CallGraphFrom\n\n**Purpose**: Shows all functions called FROM a specified source function \u2014 the outbound call dependencies.\n\n**When to use**: When analyzing what a function does by tracing the functions it invokes. Useful for understanding call chains and identifying potential data flow paths.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "CallGraphFrom"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFunction: "<function-name>"\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A graph showing each call site within the source function and the target function being called.\n\n## CallGraphTo\n\n**Purpose**: Shows all call sites that invoke a specified target function \u2014 the inbound callers.\n\n**When to use**: When performing impact analysis to understand where a function is used, or when identifying all locations that pass data to a particular sink function.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "CallGraphTo"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n targetFunction: "<function-name>"\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A graph showing each caller function and the specific call site where the target function is invoked.\n\n## CallGraphFromTo\n\n**Purpose**: Shows the call relationship between two specific functions \u2014 whether function A calls function B (directly or transitively) and what the call path looks like.\n\n**When to use**: When investigating whether a specific source function can reach a specific sink function through the call graph. Useful for validating dataflow hypotheses before writing taint-tracking queries.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "CallGraphFromTo"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFunction: "<calling-function-name>"\n targetFunction: "<called-function-name>"\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A graph showing the call path from the source function to the target function, including intermediate call sites.\n\n## Language Support\n\n| Language | PrintAST | PrintCFG | CallGraphFrom | CallGraphTo | CallGraphFromTo |\n| ---------- | :------: | :------: | :-----------: | :---------: | :-------------: |\n| actions | \u2713 | \u2713 | | | |\n| cpp | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| csharp | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| go | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| java | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| javascript | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| python | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| ruby | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| rust | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| swift | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n\nNote: The `actions` language supports PrintAST and PrintCFG only (no call graph queries).\n\n## Recommended Workflow\n\nUse the `tools_query_workflow` prompt for a guided step-by-step workflow:\n\n1. **Identify or create a database**: Use `list_codeql_databases` or `codeql_database_create`\n2. **Run PrintAST**: Understand how the source code maps to QL classes\n3. **Run PrintCFG**: Understand control flow for the functions of interest\n4. **Run CallGraphFrom / CallGraphTo**: Trace call relationships to identify sources and sinks\n5. **Run CallGraphFromTo**: Verify specific source-to-sink call paths\n6. **Write detection queries**: Use the insights from steps 2\u20135 to select the right QL classes and predicates\n\n## Related Resources\n\n- `codeql://learning/query-basics` \u2014 QL query writing reference (syntax, metadata, patterns, testing)\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://server/tools` \u2014 Complete tool reference\n- `codeql://learning/test-driven-development` \u2014 TDD workflow for CodeQL queries\n- `codeql://languages/{language}/ast` \u2014 Language-specific AST class reference\n';
197311
197548
 
197312
197549
  // src/resources/server-tools.md
197313
- var server_tools_default = '# MCP Server Tools\n\nThis resource provides a complete reference of the default tools exposed by the CodeQL Development MCP Server. These tools wrap the CodeQL CLI and supporting utilities, enabling an LLM to develop, test, and analyze CodeQL queries programmatically.\n\n## CodeQL CLI Tools\n\n| Tool | Description |\n| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_bqrs_decode` | Decode BQRS result files to human-readable formats (text, csv, json). Supports `--result-set` and `--rows` for pagination |\n| `codeql_bqrs_info` | Get metadata about BQRS result files: result sets, column types, row counts |\n| `codeql_bqrs_interpret` | Interpret BQRS result files according to query metadata and generate output in specified formats (CSV, SARIF, graph formats) |\n| `codeql_database_analyze` | Run queries or query suites against CodeQL databases. Produces evaluator logs, BQRS, and SARIF output |\n| `codeql_database_create` | Create a CodeQL database from source code |\n| `codeql_generate_log-summary` | Create a summary of a structured JSON evaluator event log file |\n| `codeql_generate_query-help` | Generate query help documentation from QLDoc comments |\n| `codeql_pack_install` | Install CodeQL pack dependencies |\n| `codeql_pack_ls` | List CodeQL packs under a local directory path |\n| `codeql_query_compile` | Compile and validate CodeQL queries |\n| `codeql_query_format` | Automatically format CodeQL source code files |\n| `codeql_query_run` | Execute a CodeQL query against a database |\n| `codeql_resolve_database` | Resolve database path and validate database structure |\n| `codeql_resolve_files` | Find files in a directory tree, filtered by extension and glob patterns. Useful for discovering QL library files |\n| `codeql_resolve_languages` | List installed CodeQL extractor packs |\n| `codeql_resolve_library-path` | Resolve library path for CodeQL queries and libraries |\n| `codeql_resolve_metadata` | Resolve and return key-value metadata pairs from a CodeQL query source file |\n| `codeql_resolve_qlref` | Resolve `.qlref` files to their corresponding query files |\n| `codeql_resolve_queries` | List available CodeQL queries found on the local filesystem |\n| `codeql_resolve_tests` | Resolve the local filesystem paths of unit tests and/or queries under a base directory |\n| `codeql_test_accept` | Accept new test results as the expected baseline |\n| `codeql_test_extract` | Extract test databases for CodeQL query tests |\n| `codeql_test_run` | Run CodeQL query tests |\n\n## Language Server Protocol (LSP) Tools\n\n| Tool | Description |\n| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_lsp_completion` | Get code completions at a cursor position in a CodeQL file |\n| `codeql_lsp_definition` | Go to the definition of a CodeQL symbol at a given position |\n| `codeql_lsp_diagnostics` | Syntax and semantic validation of CodeQL code via the Language Server. Note: inline `ql_code` cannot resolve pack imports; use `codeql_query_compile` for files with imports |\n| `codeql_lsp_references` | Find all references to a CodeQL symbol at a given position |\n\n## Query Development Tools\n\n| Tool | Description |\n| -------------------------------- | ------------------------------------------------------------------------------------------------------------ |\n| `create_codeql_query` | Create directory structure and files for a new CodeQL query with tests |\n| `find_class_position` | Find the start/end line and column of a class for quick evaluation |\n| `find_codeql_query_files` | Find and track all files and directories related to a CodeQL query, including resolved metadata |\n| `find_predicate_position` | Find the start/end line and column of a predicate for quick evaluation |\n| `list_codeql_databases` | List CodeQL databases discovered in configured base directories |\n| `list_mrva_run_results` | List MRVA (Multi-Repository Variant Analysis) run results with per-repo details |\n| `list_query_run_results` | List query run result directories with artifact inventory. Filter by `queryName`, `language`, or `queryPath` |\n| `profile_codeql_query` | Profile the performance of a CodeQL query run against a specific database by analyzing the evaluator log |\n| `profile_codeql_query_from_logs` | Parse evaluator logs into a compact profile with line-indexed detail file for targeted read_file access |\n| `quick_evaluate` | Quick evaluate either a class or a predicate in a CodeQL query for debugging |\n| `read_database_source` | Read source file contents from a CodeQL database source archive. Omit `filePath` to list all files |\n| `register_database` | Register a CodeQL database given a local path to the database directory |\n| `search_ql_code` | Search QL source files for text or regex patterns with structured results (replaces grep for QL code) |\n| `validate_codeql_query` | Quick heuristic validation for CodeQL query structure (does not compile the query) |\n\n## SARIF Analysis Tools\n\n| Tool | Description |\n| ------------------------ | ---------------------------------------------------------------------------------------------------- |\n| `sarif_extract_rule` | Extract all data for a specific rule from multi-rule SARIF. Returns a valid SARIF JSON subset |\n| `sarif_list_rules` | List all rules in a SARIF file with result counts, severity, precision, and tags |\n| `sarif_rule_to_markdown` | Convert per-rule SARIF data to markdown with Mermaid dataflow diagrams |\n| `sarif_compare_alerts` | Compare code locations of two SARIF alerts for overlap (sink, source, any-location, full-path modes) |\n| `sarif_diff_runs` | Diff two SARIF files to find added, removed, and changed rules/results across analysis runs |\n\n### `sarif_list_rules` Response Format\n\nReturns a JSON object with per-rule result counts and metadata:\n\n```json\n{\n "totalRules": 3,\n "totalResults": 15,\n "rules": [\n {\n "ruleId": "js/sql-injection",\n "resultCount": 8,\n "name": "Database query built from user-controlled sources",\n "kind": "path-problem",\n "precision": "high",\n "severity": "8.8",\n "tags": ["security", "external/cwe/cwe-089"],\n "tool": "CodeQL",\n "toolVersion": "2.20.4"\n }\n ]\n}\n```\n\n| Field | Type | Description |\n| -------------- | ------ | ------------------------------------------------ |\n| `totalRules` | number | Total number of distinct rules in the SARIF file |\n| `totalResults` | number | Sum of `resultCount` across all rules |\n| `rules[]` | array | Per-rule summaries (see below) |\n\nEach rule object:\n\n| Field | Type | Required | Description |\n| ------------- | -------- | -------- | ---------------------------------------------------------------------------- |\n| `ruleId` | string | yes | Rule identifier (matches the CodeQL query `@id`) |\n| `resultCount` | number | yes | Number of results (findings) for this rule; `0` if defined but not triggered |\n| `name` | string | no | Display name (from `shortDescription.text`, `name`, or `id`) |\n| `kind` | string | no | Query kind (`path-problem`, `problem`, etc.) |\n| `precision` | string | no | Precision level (`high`, `medium`, `low`, `very-high`) |\n| `severity` | string | no | Security severity score (from `security-severity` property) |\n| `tags` | string[] | no | Rule tags (e.g., `security`, `external/cwe/cwe-089`) |\n| `tool` | string | no | Tool driver name (e.g., `CodeQL`) |\n| `toolVersion` | string | no | Tool driver version |\n\n## Common Tool Workflows\n\n### Create and Test a Query\n\n1. `create_codeql_query` \u2014 scaffold files\n2. `codeql_pack_install` \u2014 install dependencies\n3. `codeql_query_compile` \u2014 validate syntax\n4. `codeql_test_run` \u2014 run tests\n5. `codeql_test_accept` \u2014 accept correct results\n\n### Understand Code Structure\n\n1. `codeql_query_run` with `queryName="PrintAST"` \u2014 visualize the AST\n2. `codeql_query_run` with `queryName="PrintCFG"` \u2014 visualize control flow\n3. `codeql_query_run` with `queryName="CallGraphFrom"` / `"CallGraphTo"` \u2014 trace call relationships\n4. `codeql_query_run` with `queryName="CallGraphFromTo"` \u2014 verify source-to-sink call paths\n\n### Profile Query Performance\n\n1. `codeql_query_run` with `evaluationOutput` \u2014 run query and capture evaluator logs\n2. `profile_codeql_query_from_logs` \u2014 analyze evaluator logs: slowest predicates, RA operations, tuple count progressions, dependencies\n\n### Discover and Search QL Code\n\n1. `codeql_resolve_files` \u2014 find QL files by extension and glob patterns in library packs\n2. `search_ql_code` \u2014 search QL source files for classes, predicates, or patterns by text/regex\n3. `codeql_lsp_definition` \u2014 navigate to the definition of a discovered symbol\n4. `codeql_lsp_references` \u2014 find all usages of a symbol across a pack\n\n### Interactive Development\n\n1. `codeql_lsp_completion` \u2014 get QL code completions\n2. `codeql_lsp_definition` \u2014 navigate to definitions\n3. `codeql_lsp_references` \u2014 find all references\n4. `codeql_lsp_diagnostics` \u2014 real-time validation\n\n### Analyze and Compare Results\n\n1. `codeql_database_analyze` \u2014 run query packs and produce SARIF\n2. `sarif_list_rules` \u2014 discover rules and result counts in the SARIF\n3. `query_results_cache_lookup` with `ruleId` \u2014 find cached results by CodeQL query `@id`\n4. `sarif_extract_rule` \u2014 extract results for a specific rule from multi-rule SARIF\n5. `sarif_rule_to_markdown` \u2014 generate markdown report with Mermaid dataflow diagrams\n6. `sarif_compare_alerts` \u2014 compare two alerts for location overlap\n7. `sarif_diff_runs` \u2014 diff two SARIF files to detect behavioral changes across runs\n8. `query_results_cache_compare` with `ruleId` \u2014 compare results across databases\n\n## Tool Input Conventions\n\n- **LSP tools** use **0-based** line and column positions for input. Output uses 1-based `startLine`/`endLine`.\n- **`find_predicate_position`** and **`find_class_position`** return **1-based** positions.\n- **`workspace_uri`** for LSP tools must be a **plain directory path** to the pack root containing `codeql-pack.yml`, not a `file://` URI.\n\n## Related Resources\n\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://server/prompts` \u2014 Complete prompt reference\n- `codeql://learning/query-basics` \u2014 Query writing reference\n- `codeql://patterns/performance` \u2014 Performance profiling guide\n';
197550
+ var server_tools_default = '# MCP Server Tools\n\nThis resource provides a complete reference of the default tools exposed by the CodeQL Development MCP Server. These tools wrap the CodeQL CLI and supporting utilities, enabling an LLM to develop, test, and analyze CodeQL queries programmatically.\n\n## CodeQL CLI Tools\n\n| Tool | Description |\n| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_bqrs_decode` | Decode BQRS result files to human-readable formats (text, csv, json). Supports `--result-set` and `--rows` for pagination |\n| `codeql_bqrs_info` | Get metadata about BQRS result files: result sets, column types, row counts |\n| `codeql_bqrs_interpret` | Interpret BQRS result files according to query metadata and generate output in specified formats (CSV, SARIF, graph formats) |\n| `codeql_database_analyze` | Run queries or query suites against CodeQL databases. Produces evaluator logs, BQRS, and SARIF output |\n| `codeql_database_create` | Create a CodeQL database from source code |\n| `codeql_generate_log-summary` | Create a summary of a structured JSON evaluator event log file |\n| `codeql_generate_query-help` | Generate query help documentation from QLDoc comments |\n| `codeql_pack_install` | Install CodeQL pack dependencies |\n| `codeql_pack_ls` | List CodeQL packs under a local directory path |\n| `codeql_query_compile` | Compile and validate CodeQL queries |\n| `codeql_query_format` | Automatically format CodeQL source code files |\n| `codeql_query_run` | Execute a CodeQL query against a database |\n| `codeql_resolve_database` | Resolve database path and validate database structure |\n| `codeql_resolve_files` | Find files in a directory tree, filtered by extension and glob patterns. Useful for discovering QL library files |\n| `codeql_resolve_languages` | List installed CodeQL extractor packs |\n| `codeql_resolve_library-path` | Resolve library path for CodeQL queries and libraries |\n| `codeql_resolve_metadata` | Resolve and return key-value metadata pairs from a CodeQL query source file |\n| `codeql_resolve_qlref` | Resolve `.qlref` files to their corresponding query files |\n| `codeql_resolve_queries` | List available CodeQL queries found on the local filesystem |\n| `codeql_resolve_tests` | Resolve the local filesystem paths of unit tests and/or queries under a base directory |\n| `codeql_test_accept` | Accept new test results as the expected baseline |\n| `codeql_test_extract` | Extract test databases for CodeQL query tests |\n| `codeql_test_run` | Run CodeQL query tests |\n\n## Language Server Protocol (LSP) Tools\n\n| Tool | Description |\n| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_lsp_completion` | Get code completions at a cursor position in a CodeQL file |\n| `codeql_lsp_definition` | Go to the definition of a CodeQL symbol at a given position |\n| `codeql_lsp_diagnostics` | Syntax and semantic validation of CodeQL code via the Language Server. Note: inline `ql_code` cannot resolve pack imports; use `codeql_query_compile` for files with imports |\n| `codeql_lsp_references` | Find all references to a CodeQL symbol at a given position |\n\n## Query Development Tools\n\n| Tool | Description |\n| -------------------------------- | ------------------------------------------------------------------------------------------------------------ |\n| `create_codeql_query` | Create directory structure and files for a new CodeQL query with tests |\n| `find_class_position` | Find the start/end line and column of a class for quick evaluation |\n| `find_codeql_query_files` | Find and track all files and directories related to a CodeQL query, including resolved metadata |\n| `find_predicate_position` | Find the start/end line and column of a predicate for quick evaluation |\n| `list_codeql_databases` | List CodeQL databases discovered in configured base directories |\n| `list_mrva_run_results` | List MRVA (Multi-Repository Variant Analysis) run results with per-repo details |\n| `list_query_run_results` | List query run result directories with artifact inventory. Filter by `queryName`, `language`, or `queryPath` |\n| `profile_codeql_query` | Profile the performance of a CodeQL query run against a specific database by analyzing the evaluator log |\n| `profile_codeql_query_from_logs` | Parse evaluator logs into a compact profile with line-indexed detail file for targeted read_file access |\n| `quick_evaluate` | Quick evaluate either a class or a predicate in a CodeQL query for debugging |\n| `read_database_source` | Read source file contents from a CodeQL database source archive. Omit `filePath` to list all files |\n| `register_database` | Register a CodeQL database given a local path to the database directory |\n| `search_ql_code` | Search QL source files for text or regex patterns with structured results (replaces grep for QL code) |\n| `validate_codeql_query` | Quick heuristic validation for CodeQL query structure (does not compile the query) |\n\n## SARIF Analysis Tools\n\n| Tool | Description |\n| ------------------------- | ---------------------------------------------------------------------------------------------------- |\n| `sarif_compare_alerts` | Compare code locations of two SARIF alerts for overlap (sink, source, any-location, full-path modes) |\n| `sarif_deduplicate_rules` | Find duplicate rules across two SARIF files using fingerprint-first, full-path-fallback overlap |\n| `sarif_diff_by_commits` | Correlate SARIF results with a git diff to classify findings as "new" or "pre-existing" |\n| `sarif_diff_runs` | Diff two SARIF files to find added, removed, and changed rules/results across analysis runs |\n| `sarif_extract_rule` | Extract all data for a specific rule from multi-rule SARIF. Returns a valid SARIF JSON subset |\n| `sarif_list_rules` | List all rules in a SARIF file with result counts, severity, precision, and tags |\n| `sarif_rule_to_markdown` | Convert per-rule SARIF data to markdown with Mermaid dataflow diagrams |\n| `sarif_store` | Cache SARIF content in the session store and return a cache key for use by downstream SARIF tools |\n\n### `sarif_list_rules` Response Format\n\nReturns a JSON object with per-rule result counts and metadata:\n\n```json\n{\n "totalRules": 3,\n "totalResults": 15,\n "rules": [\n {\n "ruleId": "js/sql-injection",\n "resultCount": 8,\n "name": "Database query built from user-controlled sources",\n "kind": "path-problem",\n "precision": "high",\n "severity": "8.8",\n "tags": ["security", "external/cwe/cwe-089"],\n "tool": "CodeQL",\n "toolVersion": "2.20.4"\n }\n ]\n}\n```\n\n| Field | Type | Description |\n| -------------- | ------ | ------------------------------------------------ |\n| `totalRules` | number | Total number of distinct rules in the SARIF file |\n| `totalResults` | number | Sum of `resultCount` across all rules |\n| `rules[]` | array | Per-rule summaries (see below) |\n\nEach rule object:\n\n| Field | Type | Required | Description |\n| ------------- | -------- | -------- | ---------------------------------------------------------------------------- |\n| `ruleId` | string | yes | Rule identifier (matches the CodeQL query `@id`) |\n| `resultCount` | number | yes | Number of results (findings) for this rule; `0` if defined but not triggered |\n| `name` | string | no | Display name (from `shortDescription.text`, `name`, or `id`) |\n| `kind` | string | no | Query kind (`path-problem`, `problem`, etc.) |\n| `precision` | string | no | Precision level (`high`, `medium`, `low`, `very-high`) |\n| `severity` | string | no | Security severity score (from `security-severity` property) |\n| `tags` | string[] | no | Rule tags (e.g., `security`, `external/cwe/cwe-089`) |\n| `tool` | string | no | Tool driver name (e.g., `CodeQL`) |\n| `toolVersion` | string | no | Tool driver version |\n\n## Common Tool Workflows\n\n### Create and Test a Query\n\n1. `create_codeql_query` \u2014 scaffold files\n2. `codeql_pack_install` \u2014 install dependencies\n3. `codeql_query_compile` \u2014 validate syntax\n4. `codeql_test_run` \u2014 run tests\n5. `codeql_test_accept` \u2014 accept correct results\n\n### Understand Code Structure\n\n1. `codeql_query_run` with `queryName="PrintAST"` \u2014 visualize the AST\n2. `codeql_query_run` with `queryName="PrintCFG"` \u2014 visualize control flow\n3. `codeql_query_run` with `queryName="CallGraphFrom"` / `"CallGraphTo"` \u2014 trace call relationships\n4. `codeql_query_run` with `queryName="CallGraphFromTo"` \u2014 verify source-to-sink call paths\n\n### Profile Query Performance\n\n1. `codeql_query_run` with `evaluationOutput` \u2014 run query and capture evaluator logs\n2. `profile_codeql_query_from_logs` \u2014 analyze evaluator logs: slowest predicates, RA operations, tuple count progressions, dependencies\n\n### Discover and Search QL Code\n\n1. `codeql_resolve_files` \u2014 find QL files by extension and glob patterns in library packs\n2. `search_ql_code` \u2014 search QL source files for classes, predicates, or patterns by text/regex\n3. `codeql_lsp_definition` \u2014 navigate to the definition of a discovered symbol\n4. `codeql_lsp_references` \u2014 find all usages of a symbol across a pack\n\n### Interactive Development\n\n1. `codeql_lsp_completion` \u2014 get QL code completions\n2. `codeql_lsp_definition` \u2014 navigate to definitions\n3. `codeql_lsp_references` \u2014 find all references\n4. `codeql_lsp_diagnostics` \u2014 real-time validation\n\n### Analyze and Compare Results\n\n1. `codeql_database_analyze` \u2014 run query packs and produce SARIF\n2. `sarif_list_rules` \u2014 discover rules and result counts in the SARIF\n3. `query_results_cache_lookup` with `ruleId` \u2014 find cached results by CodeQL query `@id`\n4. `sarif_extract_rule` \u2014 extract results for a specific rule from multi-rule SARIF\n5. `sarif_rule_to_markdown` \u2014 generate markdown report with Mermaid dataflow diagrams\n6. `sarif_compare_alerts` \u2014 compare two alerts for location overlap\n7. `sarif_diff_runs` \u2014 diff two SARIF files to detect behavioral changes across runs\n8. `sarif_diff_by_commits` \u2014 correlate SARIF results with git diff to triage new vs pre-existing\n9. `query_results_cache_compare` with `ruleId` \u2014 compare results across databases\n\n## Tool Input Conventions\n\n- **LSP tools** use **0-based** line and column positions for input. Output uses 1-based `startLine`/`endLine`.\n- **`find_predicate_position`** and **`find_class_position`** return **1-based** positions.\n- **`workspace_uri`** for LSP tools must be a **plain directory path** to the pack root containing `codeql-pack.yml`, not a `file://` URI.\n\n## Related Resources\n\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://server/prompts` \u2014 Complete prompt reference\n- `codeql://learning/query-basics` \u2014 Query writing reference\n- `codeql://patterns/performance` \u2014 Performance profiling guide\n';
197314
197551
 
197315
197552
  // src/lib/resources.ts
197316
197553
  function getLearningQueryBasics() {
@@ -197547,7 +197784,7 @@ import { pathToFileURL as pathToFileURL3 } from "url";
197547
197784
  // src/tools/lsp/lsp-server-helper.ts
197548
197785
  init_server_manager();
197549
197786
  init_logger();
197550
- import { isAbsolute as isAbsolute5, resolve as resolve11 } from "path";
197787
+ import { isAbsolute as isAbsolute6, resolve as resolve11 } from "path";
197551
197788
  import { pathToFileURL as pathToFileURL2 } from "url";
197552
197789
  async function getInitializedLanguageServer(opts = {}) {
197553
197790
  const { packageRootDir: pkgRoot, getUserWorkspaceDir: getUserWorkspaceDir2 } = await Promise.resolve().then(() => (init_package_paths(), package_paths_exports));
@@ -197563,7 +197800,7 @@ async function getInitializedLanguageServer(opts = {}) {
197563
197800
  const server = await manager.getLanguageServer(config2);
197564
197801
  let effectiveUri = opts.workspaceUri;
197565
197802
  if (effectiveUri && !effectiveUri.startsWith("file://")) {
197566
- const absWorkspace = isAbsolute5(effectiveUri) ? effectiveUri : resolve11(getUserWorkspaceDir2(), effectiveUri);
197803
+ const absWorkspace = isAbsolute6(effectiveUri) ? effectiveUri : resolve11(getUserWorkspaceDir2(), effectiveUri);
197567
197804
  effectiveUri = pathToFileURL2(absWorkspace).href;
197568
197805
  }
197569
197806
  effectiveUri = effectiveUri ?? pathToFileURL2(resolve11(pkgRoot, "ql")).href;
@@ -197728,7 +197965,7 @@ function registerLspDiagnosticsTool(server) {
197728
197965
  init_logger();
197729
197966
  init_package_paths();
197730
197967
  import { readFile as readFile3 } from "fs/promises";
197731
- import { isAbsolute as isAbsolute6, resolve as resolve12 } from "path";
197968
+ import { isAbsolute as isAbsolute7, resolve as resolve12 } from "path";
197732
197969
  import { pathToFileURL as pathToFileURL4 } from "url";
197733
197970
  async function getInitializedServer(params) {
197734
197971
  return getInitializedLanguageServer({
@@ -197737,7 +197974,7 @@ async function getInitializedServer(params) {
197737
197974
  });
197738
197975
  }
197739
197976
  function prepareDocumentPosition(params) {
197740
- const absPath = isAbsolute6(params.filePath) ? params.filePath : resolve12(getUserWorkspaceDir(), params.filePath);
197977
+ const absPath = isAbsolute7(params.filePath) ? params.filePath : resolve12(getUserWorkspaceDir(), params.filePath);
197741
197978
  const docUri = pathToFileURL4(absPath).href;
197742
197979
  return { absPath, docUri };
197743
197980
  }
@@ -198167,7 +198404,7 @@ function registerLanguageResources(server) {
198167
198404
 
198168
198405
  // src/prompts/workflow-prompts.ts
198169
198406
  import { access as access2 } from "fs/promises";
198170
- import { basename as basename9, isAbsolute as isAbsolute7, normalize, relative as relative2, resolve as resolve13, sep as sep3 } from "path";
198407
+ import { basename as basename10, isAbsolute as isAbsolute8, normalize, relative as relative3, resolve as resolve13, sep as sep4 } from "path";
198171
198408
  import { fileURLToPath as fileURLToPath3 } from "url";
198172
198409
 
198173
198410
  // src/prompts/constants.ts
@@ -198187,13 +198424,13 @@ var SUPPORTED_LANGUAGES = [
198187
198424
  // src/prompts/prompt-completions.ts
198188
198425
  import { readdir, readFile as readFile4 } from "fs/promises";
198189
198426
  import { homedir as homedir2 } from "os";
198190
- import { dirname as dirname9, join as join22, relative, sep as sep2 } from "path";
198427
+ import { dirname as dirname9, join as join22, relative as relative2, sep as sep3 } from "path";
198191
198428
  init_logger();
198192
198429
  init_package_paths();
198193
198430
  var MAX_FILE_COMPLETIONS = 50;
198194
198431
  var MAX_SCAN_DEPTH = 8;
198195
198432
  var CACHE_TTL_MS = 5e3;
198196
- var SKIP_DIRS3 = getScanExcludeDirs();
198433
+ var SKIP_DIRS2 = getScanExcludeDirs();
198197
198434
  var scanCache = /* @__PURE__ */ new Map();
198198
198435
  function getCachedResults(cacheKey2) {
198199
198436
  const entry = scanCache.get(cacheKey2);
@@ -198221,14 +198458,14 @@ async function findFilesByExtension(dir, baseDir, extensions, maxDepth, results)
198221
198458
  if (results.length >= MAX_FILE_COMPLETIONS) break;
198222
198459
  const fullPath = join22(dir, entry.name);
198223
198460
  if (entry.isDirectory()) {
198224
- if (SKIP_DIRS3.has(entry.name)) {
198461
+ if (SKIP_DIRS2.has(entry.name)) {
198225
198462
  continue;
198226
198463
  }
198227
198464
  await findFilesByExtension(fullPath, baseDir, extensions, maxDepth - 1, results);
198228
198465
  } else if (entry.isFile()) {
198229
198466
  const lower = entry.name.toLowerCase();
198230
198467
  if (extensions.some((ext) => lower.endsWith(ext))) {
198231
- results.push(relative(baseDir, fullPath));
198468
+ results.push(relative2(baseDir, fullPath));
198232
198469
  }
198233
198470
  }
198234
198471
  }
@@ -198312,7 +198549,7 @@ async function completeDatabasePath(value) {
198312
198549
  }
198313
198550
  const lower = (value || "").toLowerCase();
198314
198551
  const filtered = allResults.filter((p) => {
198315
- const lastSeg = p.split(sep2).pop() ?? "";
198552
+ const lastSeg = p.split(sep3).pop() ?? "";
198316
198553
  return p.toLowerCase().includes(lower) || lastSeg.toLowerCase().includes(lower);
198317
198554
  }).sort();
198318
198555
  return filtered.slice(0, MAX_FILE_COMPLETIONS);
@@ -198334,7 +198571,7 @@ async function findDatabaseDirs(dir, _baseDir, maxDepth, results) {
198334
198571
  }
198335
198572
  for (const entry of entries) {
198336
198573
  if (results.length >= MAX_FILE_COMPLETIONS) break;
198337
- if (entry.isDirectory() && !SKIP_DIRS3.has(entry.name)) {
198574
+ if (entry.isDirectory() && !SKIP_DIRS2.has(entry.name)) {
198338
198575
  await findDatabaseDirs(join22(dir, entry.name), _baseDir, maxDepth - 1, results);
198339
198576
  }
198340
198577
  }
@@ -198357,11 +198594,11 @@ async function completePackRoot(value) {
198357
198594
  (e) => e.isFile() && e.name === "codeql-pack.yml"
198358
198595
  );
198359
198596
  if (hasPackYml) {
198360
- results.push(relative(workspace, dir) || ".");
198597
+ results.push(relative2(workspace, dir) || ".");
198361
198598
  }
198362
198599
  for (const entry of entries) {
198363
198600
  if (results.length >= MAX_FILE_COMPLETIONS) break;
198364
- if (entry.isDirectory() && !SKIP_DIRS3.has(entry.name)) {
198601
+ if (entry.isDirectory() && !SKIP_DIRS2.has(entry.name)) {
198365
198602
  await scan(join22(dir, entry.name), depth - 1);
198366
198603
  }
198367
198604
  }
@@ -198599,11 +198836,11 @@ async function resolvePromptFilePath(filePath, workspaceRoot) {
198599
198836
  }
198600
198837
  const effectiveRoot = workspaceRoot ?? getUserWorkspaceDir();
198601
198838
  const normalizedPath = normalize(effectivePath);
198602
- const inputWasAbsolute = isAbsolute7(normalizedPath);
198839
+ const inputWasAbsolute = isAbsolute8(normalizedPath);
198603
198840
  const absolutePath = inputWasAbsolute ? normalizedPath : resolve13(effectiveRoot, normalizedPath);
198604
198841
  if (!inputWasAbsolute) {
198605
- const rel = relative2(effectiveRoot, absolutePath);
198606
- if (rel === ".." || rel.startsWith(`..${sep3}`) || isAbsolute7(rel)) {
198842
+ const rel = relative3(effectiveRoot, absolutePath);
198843
+ if (rel === ".." || rel.startsWith(`..${sep4}`) || isAbsolute8(rel)) {
198607
198844
  return {
198608
198845
  blocked: true,
198609
198846
  resolvedPath: "",
@@ -198873,7 +199110,7 @@ ${content}`
198873
199110
  const langResult = await getEffectiveLanguage("workshop_creation_workflow", language, resolvedQueryPath);
198874
199111
  const effectiveLanguage = langResult.language;
198875
199112
  if (langResult.warning) warnings.push(langResult.warning);
198876
- const derivedName = workshopName || basename9(resolvedQueryPath).replace(/\.(ql|qlref)$/, "").toLowerCase().replace(/[^a-z0-9]+/g, "-") || "codeql-workshop";
199113
+ const derivedName = workshopName || basename10(resolvedQueryPath).replace(/\.(ql|qlref)$/, "").toLowerCase().replace(/[^a-z0-9]+/g, "-") || "codeql-workshop";
198877
199114
  const contextSection = buildWorkshopContext(
198878
199115
  resolvedQueryPath,
198879
199116
  effectiveLanguage ?? "unknown",
@@ -200247,13 +200484,6 @@ function generateListRecommendations(sessions) {
200247
200484
  // src/tools/annotation-tools.ts
200248
200485
  init_logger();
200249
200486
  function registerAnnotationTools(server) {
200250
- const config2 = sessionDataManager.getConfig();
200251
- if (!config2.enableAnnotationTools) {
200252
- logger.info(
200253
- "Annotation tools are disabled (opt-in). Set ENABLE_ANNOTATION_TOOLS=true to enable annotation_* tools."
200254
- );
200255
- return;
200256
- }
200257
200487
  registerAnnotationCreateTool(server);
200258
200488
  registerAnnotationGetTool(server);
200259
200489
  registerAnnotationListTool(server);
@@ -200388,13 +200618,6 @@ function registerAnnotationSearchTool(server) {
200388
200618
  init_logger();
200389
200619
  var AUDIT_CATEGORY = "audit-finding";
200390
200620
  function registerAuditTools(server) {
200391
- const config2 = sessionDataManager.getConfig();
200392
- if (!config2.enableAnnotationTools) {
200393
- logger.info(
200394
- "Audit tools are disabled (opt-in). Set ENABLE_ANNOTATION_TOOLS=true to enable audit_* and annotation_* tools."
200395
- );
200396
- return;
200397
- }
200398
200621
  registerAuditStoreFindingsTool(server);
200399
200622
  registerAuditListFindingsTool(server);
200400
200623
  registerAuditAddNotesTool(server);
@@ -200562,13 +200785,6 @@ function registerAuditClearRepoTool(server) {
200562
200785
  // src/tools/cache-tools.ts
200563
200786
  init_logger();
200564
200787
  function registerCacheTools(server) {
200565
- const config2 = sessionDataManager.getConfig();
200566
- if (!config2.enableAnnotationTools) {
200567
- logger.info(
200568
- "Cache tools are disabled (opt-in). Set ENABLE_ANNOTATION_TOOLS=true to enable query_results_cache_* tools."
200569
- );
200570
- return;
200571
- }
200572
200788
  registerQueryResultsCacheLookupTool(server);
200573
200789
  registerQueryResultsCacheRetrieveTool(server);
200574
200790
  registerQueryResultsCacheClearTool(server);
@@ -200615,8 +200831,14 @@ function registerQueryResultsCacheRetrieveTool(server) {
200615
200831
  "Retrieve cached query results with optional subset selection. Supports line ranges (for graphtext/CSV) and SARIF result indices and file filtering to return only the relevant portion.",
200616
200832
  {
200617
200833
  cacheKey: external_exports.string().describe("The cache key of the result to retrieve."),
200618
- lineRange: external_exports.tuple([external_exports.number().int().min(1), external_exports.number().int().min(1)]).refine(([start, end]) => start <= end, { message: "lineRange start must be <= end" }).optional().describe("Line range [start, end] (1-indexed, inclusive). For graphtext/CSV output only."),
200619
- resultIndices: external_exports.tuple([external_exports.number().int().min(0), external_exports.number().int().min(0)]).refine(([start, end]) => start <= end, { message: "resultIndices start must be <= end" }).optional().describe("SARIF result index range [start, end] (0-indexed, inclusive). For SARIF output only."),
200834
+ lineRange: external_exports.object({
200835
+ start: external_exports.number().int().min(1).describe("First line to include (1-indexed, inclusive)."),
200836
+ end: external_exports.number().int().min(1).describe("Last line to include (1-indexed, inclusive).")
200837
+ }).refine(({ start, end }) => start <= end, { message: "lineRange.start must be <= lineRange.end" }).optional().describe("Line range {start, end} (1-indexed, inclusive). For graphtext/CSV output only."),
200838
+ resultIndices: external_exports.object({
200839
+ start: external_exports.number().int().min(0).describe("First SARIF result index to include (0-indexed, inclusive)."),
200840
+ end: external_exports.number().int().min(0).describe("Last SARIF result index to include (0-indexed, inclusive).")
200841
+ }).refine(({ start, end }) => start <= end, { message: "resultIndices.start must be <= resultIndices.end" }).optional().describe("SARIF result index range {start, end} (0-indexed, inclusive). For SARIF output only."),
200620
200842
  fileFilter: external_exports.string().optional().describe("For SARIF: only include results whose file path contains this string."),
200621
200843
  maxLines: external_exports.number().int().positive().optional().describe("Maximum number of lines to return for line-based formats (default: 500)."),
200622
200844
  maxResults: external_exports.number().int().positive().optional().describe("Maximum number of SARIF results to return (default: 100).")
@@ -200630,7 +200852,7 @@ function registerQueryResultsCacheRetrieveTool(server) {
200630
200852
  const isSarif = meta.outputFormat.includes("sarif");
200631
200853
  if (isSarif) {
200632
200854
  const subset2 = store.getCacheSarifSubset(cacheKey2, {
200633
- resultIndices,
200855
+ resultIndices: resultIndices ? [resultIndices.start, resultIndices.end] : void 0,
200634
200856
  fileFilter,
200635
200857
  maxResults
200636
200858
  });
@@ -200661,7 +200883,7 @@ function registerQueryResultsCacheRetrieveTool(server) {
200661
200883
  };
200662
200884
  }
200663
200885
  const subset = store.getCacheContentSubset(cacheKey2, {
200664
- lineRange,
200886
+ lineRange: lineRange ? [lineRange.start, lineRange.end] : void 0,
200665
200887
  maxLines: maxLines ?? 500
200666
200888
  });
200667
200889
  if (!subset) {
@@ -200758,26 +200980,25 @@ function registerQueryResultsCacheCompareTool(server) {
200758
200980
  import { readFileSync as readFileSync13 } from "fs";
200759
200981
  init_logger();
200760
200982
  function registerSarifTools(server) {
200761
- const config2 = sessionDataManager.getConfig();
200762
- if (!config2.enableAnnotationTools) {
200763
- logger.info(
200764
- "SARIF tools are disabled (opt-in). Set ENABLE_ANNOTATION_TOOLS=true to enable sarif_* tools."
200765
- );
200766
- return;
200767
- }
200983
+ registerSarifCompareAlertsTool(server);
200984
+ registerSarifDeduplicateRulesTool(server);
200985
+ registerSarifDiffByCommitsTool(server);
200986
+ registerSarifDiffRunsTool(server);
200768
200987
  registerSarifExtractRuleTool(server);
200769
200988
  registerSarifListRulesTool(server);
200770
200989
  registerSarifRuleToMarkdownTool(server);
200771
- registerSarifCompareAlertsTool(server);
200772
- registerSarifDiffRunsTool(server);
200990
+ registerSarifStoreTool(server);
200773
200991
  logger.info("Registered SARIF analysis tools");
200774
200992
  }
200775
- function loadSarif(sarifPath, cacheKey2) {
200776
- if (!sarifPath && !cacheKey2) {
200777
- return { error: "Either sarifPath or cacheKey is required." };
200993
+ function loadSarif(opts) {
200994
+ const { cacheKey: cacheKey2, inlineContent, sarifPath } = opts;
200995
+ if (!sarifPath && !cacheKey2 && !inlineContent) {
200996
+ return { error: "No SARIF source provided." };
200778
200997
  }
200779
200998
  let content;
200780
- if (cacheKey2) {
200999
+ if (inlineContent) {
201000
+ content = inlineContent;
201001
+ } else if (cacheKey2) {
200781
201002
  const store = sessionDataManager.getStore();
200782
201003
  const cached2 = store.getCacheContent(cacheKey2);
200783
201004
  if (!cached2) {
@@ -200821,7 +201042,7 @@ function registerSarifExtractRuleTool(server) {
200821
201042
  sarifPath: external_exports.string().optional().describe("Path to the SARIF file.")
200822
201043
  },
200823
201044
  async ({ sarifPath, cacheKey: cacheKey2, ruleId }) => {
200824
- const loaded = loadSarif(sarifPath, cacheKey2);
201045
+ const loaded = loadSarif({ sarifPath, cacheKey: cacheKey2 });
200825
201046
  if (loaded.error) {
200826
201047
  return { content: [{ type: "text", text: loaded.error }] };
200827
201048
  }
@@ -200858,7 +201079,7 @@ function registerSarifListRulesTool(server) {
200858
201079
  sarifPath: external_exports.string().optional().describe("Path to the SARIF file.")
200859
201080
  },
200860
201081
  async ({ sarifPath, cacheKey: cacheKey2 }) => {
200861
- const loaded = loadSarif(sarifPath, cacheKey2);
201082
+ const loaded = loadSarif({ sarifPath, cacheKey: cacheKey2 });
200862
201083
  if (loaded.error) {
200863
201084
  return { content: [{ type: "text", text: loaded.error }] };
200864
201085
  }
@@ -200886,7 +201107,7 @@ function registerSarifRuleToMarkdownTool(server) {
200886
201107
  sarifPath: external_exports.string().optional().describe("Path to the SARIF file.")
200887
201108
  },
200888
201109
  async ({ sarifPath, cacheKey: cacheKey2, ruleId }) => {
200889
- const loaded = loadSarif(sarifPath, cacheKey2);
201110
+ const loaded = loadSarif({ sarifPath, cacheKey: cacheKey2 });
200890
201111
  if (loaded.error) {
200891
201112
  return { content: [{ type: "text", text: loaded.error }] };
200892
201113
  }
@@ -200917,18 +201138,18 @@ function registerSarifCompareAlertsTool(server) {
200917
201138
  });
200918
201139
  server.tool(
200919
201140
  "sarif_compare_alerts",
200920
- "Compare code locations of two SARIF alerts to detect overlap. Supports sink, source, any-location, and full-path comparison modes.",
201141
+ "Compare code locations of two SARIF alerts to detect overlap. Supports sink, source, any-location, full-path, and fingerprint comparison modes.",
200921
201142
  {
200922
201143
  alertA: alertSpecSchema.describe("First alert to compare."),
200923
201144
  alertB: alertSpecSchema.describe("Second alert to compare."),
200924
- overlapMode: external_exports.enum(["sink", "source", "any-location", "full-path"]).optional().default("sink").describe('Comparison mode: "sink" (primary locations), "source" (first dataflow step), "any-location" (all locations), "full-path" (structural path similarity).')
201145
+ overlapMode: external_exports.enum(["sink", "source", "any-location", "full-path", "fingerprint"]).optional().default("sink").describe('Comparison mode: "sink" (primary locations), "source" (first dataflow step), "any-location" (all locations), "full-path" (structural path similarity), "fingerprint" (partialFingerprints match, falls back to full-path).')
200925
201146
  },
200926
201147
  async ({ alertA, alertB, overlapMode }) => {
200927
- const loadedA = loadSarif(alertA.sarifPath, alertA.cacheKey);
201148
+ const loadedA = loadSarif({ sarifPath: alertA.sarifPath, cacheKey: alertA.cacheKey });
200928
201149
  if (loadedA.error) {
200929
201150
  return { content: [{ type: "text", text: `Alert A: ${loadedA.error}` }] };
200930
201151
  }
200931
- const loadedB = loadSarif(alertB.sarifPath, alertB.cacheKey);
201152
+ const loadedB = loadSarif({ sarifPath: alertB.sarifPath, cacheKey: alertB.cacheKey });
200932
201153
  if (loadedB.error) {
200933
201154
  return { content: [{ type: "text", text: `Alert B: ${loadedB.error}` }] };
200934
201155
  }
@@ -200967,6 +201188,12 @@ function registerSarifCompareAlertsTool(server) {
200967
201188
  if (overlap.pathSimilarity !== void 0) {
200968
201189
  response.pathSimilarity = overlap.pathSimilarity;
200969
201190
  }
201191
+ if (overlap.fingerprintMatch !== void 0) {
201192
+ response.fingerprintMatch = overlap.fingerprintMatch;
201193
+ }
201194
+ if (overlap.matchedFingerprints !== void 0) {
201195
+ response.matchedFingerprints = overlap.matchedFingerprints;
201196
+ }
200970
201197
  return {
200971
201198
  content: [{
200972
201199
  type: "text",
@@ -200976,6 +201203,81 @@ function registerSarifCompareAlertsTool(server) {
200976
201203
  }
200977
201204
  );
200978
201205
  }
201206
+ function parseGitDiffOutput(diffOutput) {
201207
+ const files = [];
201208
+ let currentFile = null;
201209
+ for (const line of diffOutput.split(/\r?\n/)) {
201210
+ if (line.startsWith("+++ b/")) {
201211
+ if (currentFile) files.push(currentFile);
201212
+ currentFile = { hunks: [], path: line.substring(6) };
201213
+ continue;
201214
+ }
201215
+ if (currentFile && line.startsWith("@@")) {
201216
+ const match = line.match(/@@ [^ ]+ \+(\d+)(?:,(\d+))? @@/);
201217
+ if (match) {
201218
+ currentFile.hunksParsed = true;
201219
+ const startLine = parseInt(match[1], 10);
201220
+ const lineCount = match[2] !== void 0 ? parseInt(match[2], 10) : 1;
201221
+ if (lineCount > 0) {
201222
+ currentFile.hunks.push({ startLine, lineCount });
201223
+ }
201224
+ }
201225
+ }
201226
+ }
201227
+ if (currentFile) files.push(currentFile);
201228
+ return files;
201229
+ }
201230
+ function registerSarifDiffByCommitsTool(server) {
201231
+ server.tool(
201232
+ "sarif_diff_by_commits",
201233
+ 'Correlate SARIF results with a git diff to classify findings as "new" (introduced in the diff) or "pre-existing". Accepts a SARIF file and a git ref range (e.g. "main..HEAD"). Supports file-level or line-level granularity.',
201234
+ {
201235
+ cacheKey: external_exports.string().optional().describe("Cache key to read SARIF from (alternative to sarifPath)."),
201236
+ granularity: external_exports.enum(["file", "line"]).optional().default("file").describe('Matching granularity: "file" classifies any result in a changed file as new; "line" additionally checks that the result line falls within a changed hunk. Default: "file".'),
201237
+ refRange: external_exports.string().describe('Git ref range for the diff (e.g. "main..HEAD", "abc123..def456"). Passed directly to `git diff`.'),
201238
+ repoPath: external_exports.string().optional().describe("Path to the git repository. Defaults to the current working directory."),
201239
+ sarifPath: external_exports.string().optional().describe("Path to the SARIF file.")
201240
+ },
201241
+ async ({ sarifPath, cacheKey: cacheKey2, refRange, repoPath, granularity }) => {
201242
+ if (/^\s*-/.test(refRange) || /\s/.test(refRange)) {
201243
+ return {
201244
+ content: [{
201245
+ type: "text",
201246
+ text: 'Invalid refRange: must not start with "-" or contain whitespace.'
201247
+ }]
201248
+ };
201249
+ }
201250
+ const loaded = loadSarif({ sarifPath, cacheKey: cacheKey2 });
201251
+ if (loaded.error) {
201252
+ return { content: [{ type: "text", text: loaded.error }] };
201253
+ }
201254
+ const { executeCLICommand: executeCLICommand2 } = await Promise.resolve().then(() => (init_cli_executor(), cli_executor_exports));
201255
+ const gitArgs = ["diff", "--unified=0", "--diff-filter=ACMR", "--no-color", refRange];
201256
+ const gitResult = await executeCLICommand2({
201257
+ args: gitArgs,
201258
+ command: "git",
201259
+ cwd: repoPath
201260
+ });
201261
+ if (!gitResult.success) {
201262
+ return {
201263
+ content: [{
201264
+ type: "text",
201265
+ text: `git diff failed: ${gitResult.error ?? gitResult.stderr}`
201266
+ }]
201267
+ };
201268
+ }
201269
+ const diffFiles = parseGitDiffOutput(gitResult.stdout);
201270
+ const g = granularity;
201271
+ const result = diffSarifByCommits(loaded.sarif, diffFiles, refRange, g);
201272
+ return {
201273
+ content: [{
201274
+ type: "text",
201275
+ text: JSON.stringify(result, null, 2)
201276
+ }]
201277
+ };
201278
+ }
201279
+ );
201280
+ }
200979
201281
  function registerSarifDiffRunsTool(server) {
200980
201282
  server.tool(
200981
201283
  "sarif_diff_runs",
@@ -200989,11 +201291,11 @@ function registerSarifDiffRunsTool(server) {
200989
201291
  sarifPathB: external_exports.string().optional().describe("Path to the second (comparison) SARIF file.")
200990
201292
  },
200991
201293
  async ({ sarifPathA, sarifPathB, cacheKeyA, cacheKeyB, labelA, labelB }) => {
200992
- const loadedA = loadSarif(sarifPathA, cacheKeyA);
201294
+ const loadedA = loadSarif({ sarifPath: sarifPathA, cacheKey: cacheKeyA });
200993
201295
  if (loadedA.error) {
200994
201296
  return { content: [{ type: "text", text: `Run A: ${loadedA.error}` }] };
200995
201297
  }
200996
- const loadedB = loadSarif(sarifPathB, cacheKeyB);
201298
+ const loadedB = loadSarif({ sarifPath: sarifPathB, cacheKey: cacheKeyB });
200997
201299
  if (loadedB.error) {
200998
201300
  return { content: [{ type: "text", text: `Run B: ${loadedB.error}` }] };
200999
201301
  }
@@ -201011,6 +201313,165 @@ function registerSarifDiffRunsTool(server) {
201011
201313
  }
201012
201314
  );
201013
201315
  }
201316
+ function registerSarifStoreTool(server) {
201317
+ server.tool(
201318
+ "sarif_store",
201319
+ "Store SARIF content in the session cache for use by other sarif_* tools. Returns a cache key that can be passed to sarifPath/cacheKey parameters of other tools.",
201320
+ {
201321
+ label: external_exports.string().optional().describe('Human-readable label for this SARIF (e.g. "dubbo-java-2025-03").'),
201322
+ sarifContent: external_exports.string().optional().describe("SARIF JSON content as a string (alternative to sarifPath)."),
201323
+ sarifPath: external_exports.string().optional().describe("Path to a SARIF file on disk.")
201324
+ },
201325
+ async ({ sarifContent, sarifPath, label }) => {
201326
+ if (!sarifContent && !sarifPath) {
201327
+ return { content: [{ type: "text", text: "Either sarifContent or sarifPath is required." }] };
201328
+ }
201329
+ let content;
201330
+ if (sarifPath) {
201331
+ try {
201332
+ content = readFileSync13(sarifPath, "utf8");
201333
+ } catch {
201334
+ return { content: [{ type: "text", text: `Failed to read SARIF file: ${sarifPath}` }] };
201335
+ }
201336
+ } else {
201337
+ content = sarifContent;
201338
+ }
201339
+ const loaded = loadSarif({ inlineContent: content });
201340
+ if (loaded.error) {
201341
+ return { content: [{ type: "text", text: loaded.error }] };
201342
+ }
201343
+ const { createHash: createHash3 } = await import("crypto");
201344
+ const hash = createHash3("sha256").update(content).digest("hex").slice(0, 16);
201345
+ const cacheKey2 = `sarif-store-${hash}`;
201346
+ const sarif = loaded.sarif;
201347
+ const resultCount = sarif.runs[0]?.results?.length ?? 0;
201348
+ const ruleCount = sarif.runs[0]?.tool.driver.rules?.length ?? 0;
201349
+ const toolName = sarif.runs[0]?.tool.driver.name ?? "unknown";
201350
+ const store = sessionDataManager.getStore();
201351
+ store.putCacheEntry({
201352
+ cacheKey: cacheKey2,
201353
+ codeqlVersion: sarif.runs[0]?.tool.driver.version ?? "unknown",
201354
+ databasePath: sarifPath ?? "inline",
201355
+ language: "sarif",
201356
+ outputFormat: "sarif",
201357
+ queryName: "sarif_store",
201358
+ queryPath: sarifPath ?? "inline",
201359
+ resultContent: content,
201360
+ resultCount
201361
+ });
201362
+ return {
201363
+ content: [{
201364
+ type: "text",
201365
+ text: JSON.stringify({
201366
+ cacheKey: cacheKey2,
201367
+ label: label ?? null,
201368
+ resultCount,
201369
+ ruleCount,
201370
+ source: sarifPath ? "file" : "inline",
201371
+ toolName
201372
+ }, null, 2)
201373
+ }]
201374
+ };
201375
+ }
201376
+ );
201377
+ }
201378
+ function registerSarifDeduplicateRulesTool(server) {
201379
+ server.tool(
201380
+ "sarif_deduplicate_rules",
201381
+ "Identify duplicate alerts across two SARIF files by comparing rules pairwise. Uses fingerprint matching first, then full-path location overlap as fallback. Useful for cleanup after query changes or pack upgrades.",
201382
+ {
201383
+ cacheKeyA: external_exports.string().optional().describe("Cache key for the first SARIF."),
201384
+ cacheKeyB: external_exports.string().optional().describe("Cache key for the second SARIF."),
201385
+ overlapThreshold: external_exports.number().min(0).max(1).optional().default(0.8).describe("Minimum overlap score (0-1) to consider a rule pair as duplicates. Default: 0.8."),
201386
+ sarifPathA: external_exports.string().optional().describe("Path to the first SARIF file."),
201387
+ sarifPathB: external_exports.string().optional().describe("Path to the second SARIF file.")
201388
+ },
201389
+ async ({ sarifPathA, sarifPathB, cacheKeyA, cacheKeyB, overlapThreshold }) => {
201390
+ const loadedA = loadSarif({ sarifPath: sarifPathA, cacheKey: cacheKeyA });
201391
+ if (loadedA.error) {
201392
+ return { content: [{ type: "text", text: `SARIF A: ${loadedA.error}` }] };
201393
+ }
201394
+ const loadedB = loadSarif({ sarifPath: sarifPathB, cacheKey: cacheKeyB });
201395
+ if (loadedB.error) {
201396
+ return { content: [{ type: "text", text: `SARIF B: ${loadedB.error}` }] };
201397
+ }
201398
+ const rulesA = listSarifRules(loadedA.sarif);
201399
+ const rulesB = listSarifRules(loadedB.sarif);
201400
+ const duplicateGroups = [];
201401
+ const ruleDataA = /* @__PURE__ */ new Map();
201402
+ for (const rA of rulesA) {
201403
+ if (rA.resultCount === 0) continue;
201404
+ const extracted = extractRuleFromSarif(loadedA.sarif, rA.ruleId);
201405
+ ruleDataA.set(rA.ruleId, {
201406
+ results: extracted.runs[0]?.results ?? [],
201407
+ ruleObj: extracted.runs[0]?.tool.driver.rules?.[0] ?? { id: rA.ruleId }
201408
+ });
201409
+ }
201410
+ const ruleDataB = /* @__PURE__ */ new Map();
201411
+ for (const rB of rulesB) {
201412
+ if (rB.resultCount === 0) continue;
201413
+ const extracted = extractRuleFromSarif(loadedB.sarif, rB.ruleId);
201414
+ ruleDataB.set(rB.ruleId, {
201415
+ results: extracted.runs[0]?.results ?? [],
201416
+ ruleObj: extracted.runs[0]?.tool.driver.rules?.[0] ?? { id: rB.ruleId }
201417
+ });
201418
+ }
201419
+ for (const rA of rulesA) {
201420
+ const dataA = ruleDataA.get(rA.ruleId);
201421
+ if (!dataA) continue;
201422
+ for (const rB of rulesB) {
201423
+ const dataB = ruleDataB.get(rB.ruleId);
201424
+ if (!dataB) continue;
201425
+ const { results: resultsA, ruleObj: ruleObjA } = dataA;
201426
+ const { results: resultsB, ruleObj: ruleObjB } = dataB;
201427
+ const overlaps = findOverlappingAlerts(resultsA, ruleObjA, resultsB, ruleObjB, "full-path");
201428
+ const matchedAIndices = /* @__PURE__ */ new Set();
201429
+ for (let ai = 0; ai < resultsA.length; ai++) {
201430
+ for (const rResultB of resultsB) {
201431
+ const fpResult = computeFingerprintOverlap(resultsA[ai], rResultB);
201432
+ if (fpResult.fingerprintMatch) {
201433
+ matchedAIndices.add(ai);
201434
+ break;
201435
+ }
201436
+ }
201437
+ }
201438
+ const matchedAlerts = Math.max(overlaps.length, matchedAIndices.size);
201439
+ const minResults = Math.min(resultsA.length, resultsB.length);
201440
+ const cappedMatched = Math.min(matchedAlerts, minResults);
201441
+ const totalUnique = resultsA.length + resultsB.length - cappedMatched;
201442
+ const overlapScore = totalUnique > 0 ? cappedMatched / totalUnique : 0;
201443
+ if (overlapScore >= (overlapThreshold ?? 0.8)) {
201444
+ duplicateGroups.push({
201445
+ matchedAlerts: cappedMatched,
201446
+ overlapScore: Math.round(overlapScore * 1e3) / 1e3,
201447
+ ruleIdA: rA.ruleId,
201448
+ ruleIdB: rB.ruleId,
201449
+ totalA: resultsA.length,
201450
+ totalB: resultsB.length,
201451
+ unmatchedA: Math.max(0, resultsA.length - cappedMatched),
201452
+ unmatchedB: Math.max(0, resultsB.length - cappedMatched)
201453
+ });
201454
+ }
201455
+ }
201456
+ }
201457
+ duplicateGroups.sort((a, b) => b.overlapScore - a.overlapScore);
201458
+ return {
201459
+ content: [{
201460
+ type: "text",
201461
+ text: JSON.stringify({
201462
+ duplicateGroups,
201463
+ summary: {
201464
+ duplicatePairsFound: duplicateGroups.length,
201465
+ overlapThreshold: overlapThreshold ?? 0.8,
201466
+ totalRulesA: rulesA.length,
201467
+ totalRulesB: rulesB.length
201468
+ }
201469
+ }, null, 2)
201470
+ }]
201471
+ };
201472
+ }
201473
+ );
201474
+ }
201014
201475
 
201015
201476
  // src/lib/tool-validation.ts
201016
201477
  function formatAllValidationErrors(error2) {
@@ -201079,7 +201540,7 @@ init_package_paths();
201079
201540
  init_logger();
201080
201541
  import_dotenv.default.config({ path: resolve14(packageRootDir, ".env"), quiet: true });
201081
201542
  var PACKAGE_NAME = "codeql-development-mcp-server";
201082
- var VERSION = "2.25.2-rc1";
201543
+ var VERSION = "2.25.3";
201083
201544
  async function startServer(mode = "stdio") {
201084
201545
  logger.info(`Starting CodeQL Development MCP McpServer v${VERSION} in ${mode} mode`);
201085
201546
  const codeqlBinary = resolveCodeQLBinary();