codeql-development-mcp-server 2.24.3-rc2 → 2.25.0-rc1

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.
@@ -2242,8 +2242,8 @@ var require_resolve = __commonJS({
2242
2242
  }
2243
2243
  return count;
2244
2244
  }
2245
- function getFullPath(resolver, id = "", normalize) {
2246
- if (normalize !== false)
2245
+ function getFullPath(resolver, id = "", normalize2) {
2246
+ if (normalize2 !== false)
2247
2247
  id = normalizeId(id);
2248
2248
  const p = resolver.parse(id);
2249
2249
  return _getFullPath(resolver, p);
@@ -2991,7 +2991,7 @@ var require_compile = __commonJS({
2991
2991
  const schOrFunc = root.refs[ref];
2992
2992
  if (schOrFunc)
2993
2993
  return schOrFunc;
2994
- let _sch = resolve14.call(this, root, ref);
2994
+ let _sch = resolve15.call(this, root, ref);
2995
2995
  if (_sch === void 0) {
2996
2996
  const schema2 = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
2997
2997
  const { schemaId } = this.opts;
@@ -3018,7 +3018,7 @@ var require_compile = __commonJS({
3018
3018
  function sameSchemaEnv(s1, s2) {
3019
3019
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
3020
3020
  }
3021
- function resolve14(root, ref) {
3021
+ function resolve15(root, ref) {
3022
3022
  let sch;
3023
3023
  while (typeof (sch = this.refs[ref]) == "string")
3024
3024
  ref = sch;
@@ -3583,7 +3583,7 @@ var require_fast_uri = __commonJS({
3583
3583
  "use strict";
3584
3584
  var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils();
3585
3585
  var { SCHEMES, getSchemeHandler } = require_schemes();
3586
- function normalize(uri, options) {
3586
+ function normalize2(uri, options) {
3587
3587
  if (typeof uri === "string") {
3588
3588
  uri = /** @type {T} */
3589
3589
  serialize(parse4(uri, options), options);
@@ -3593,55 +3593,55 @@ var require_fast_uri = __commonJS({
3593
3593
  }
3594
3594
  return uri;
3595
3595
  }
3596
- function resolve14(baseURI, relativeURI, options) {
3596
+ function resolve15(baseURI, relativeURI, options) {
3597
3597
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3598
3598
  const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
3599
3599
  schemelessOptions.skipEscape = true;
3600
3600
  return serialize(resolved, schemelessOptions);
3601
3601
  }
3602
- function resolveComponent(base, relative, options, skipNormalization) {
3602
+ function resolveComponent(base, relative2, options, skipNormalization) {
3603
3603
  const target = {};
3604
3604
  if (!skipNormalization) {
3605
3605
  base = parse4(serialize(base, options), options);
3606
- relative = parse4(serialize(relative, options), options);
3606
+ relative2 = parse4(serialize(relative2, options), options);
3607
3607
  }
3608
3608
  options = options || {};
3609
- if (!options.tolerant && relative.scheme) {
3610
- target.scheme = relative.scheme;
3611
- target.userinfo = relative.userinfo;
3612
- target.host = relative.host;
3613
- target.port = relative.port;
3614
- target.path = removeDotSegments(relative.path || "");
3615
- target.query = relative.query;
3609
+ if (!options.tolerant && relative2.scheme) {
3610
+ target.scheme = relative2.scheme;
3611
+ target.userinfo = relative2.userinfo;
3612
+ target.host = relative2.host;
3613
+ target.port = relative2.port;
3614
+ target.path = removeDotSegments(relative2.path || "");
3615
+ target.query = relative2.query;
3616
3616
  } else {
3617
- if (relative.userinfo !== void 0 || relative.host !== void 0 || relative.port !== void 0) {
3618
- target.userinfo = relative.userinfo;
3619
- target.host = relative.host;
3620
- target.port = relative.port;
3621
- target.path = removeDotSegments(relative.path || "");
3622
- target.query = relative.query;
3617
+ if (relative2.userinfo !== void 0 || relative2.host !== void 0 || relative2.port !== void 0) {
3618
+ target.userinfo = relative2.userinfo;
3619
+ target.host = relative2.host;
3620
+ target.port = relative2.port;
3621
+ target.path = removeDotSegments(relative2.path || "");
3622
+ target.query = relative2.query;
3623
3623
  } else {
3624
- if (!relative.path) {
3624
+ if (!relative2.path) {
3625
3625
  target.path = base.path;
3626
- if (relative.query !== void 0) {
3627
- target.query = relative.query;
3626
+ if (relative2.query !== void 0) {
3627
+ target.query = relative2.query;
3628
3628
  } else {
3629
3629
  target.query = base.query;
3630
3630
  }
3631
3631
  } else {
3632
- if (relative.path[0] === "/") {
3633
- target.path = removeDotSegments(relative.path);
3632
+ if (relative2.path[0] === "/") {
3633
+ target.path = removeDotSegments(relative2.path);
3634
3634
  } else {
3635
3635
  if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
3636
- target.path = "/" + relative.path;
3636
+ target.path = "/" + relative2.path;
3637
3637
  } else if (!base.path) {
3638
- target.path = relative.path;
3638
+ target.path = relative2.path;
3639
3639
  } else {
3640
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative.path;
3640
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative2.path;
3641
3641
  }
3642
3642
  target.path = removeDotSegments(target.path);
3643
3643
  }
3644
- target.query = relative.query;
3644
+ target.query = relative2.query;
3645
3645
  }
3646
3646
  target.userinfo = base.userinfo;
3647
3647
  target.host = base.host;
@@ -3649,7 +3649,7 @@ var require_fast_uri = __commonJS({
3649
3649
  }
3650
3650
  target.scheme = base.scheme;
3651
3651
  }
3652
- target.fragment = relative.fragment;
3652
+ target.fragment = relative2.fragment;
3653
3653
  return target;
3654
3654
  }
3655
3655
  function equal(uriA, uriB, options) {
@@ -3819,8 +3819,8 @@ var require_fast_uri = __commonJS({
3819
3819
  }
3820
3820
  var fastUri = {
3821
3821
  SCHEMES,
3822
- normalize,
3823
- resolve: resolve14,
3822
+ normalize: normalize2,
3823
+ resolve: resolve15,
3824
3824
  resolveComponent,
3825
3825
  equal,
3826
3826
  serialize,
@@ -8862,8 +8862,8 @@ var require_resolve2 = __commonJS({
8862
8862
  }
8863
8863
  return count;
8864
8864
  }
8865
- function getFullPath(resolver, id = "", normalize) {
8866
- if (normalize !== false)
8865
+ function getFullPath(resolver, id = "", normalize2) {
8866
+ if (normalize2 !== false)
8867
8867
  id = normalizeId(id);
8868
8868
  const p = resolver.parse(id);
8869
8869
  return _getFullPath(resolver, p);
@@ -9611,7 +9611,7 @@ var require_compile2 = __commonJS({
9611
9611
  const schOrFunc = root.refs[ref];
9612
9612
  if (schOrFunc)
9613
9613
  return schOrFunc;
9614
- let _sch = resolve14.call(this, root, ref);
9614
+ let _sch = resolve15.call(this, root, ref);
9615
9615
  if (_sch === void 0) {
9616
9616
  const schema2 = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
9617
9617
  const { schemaId } = this.opts;
@@ -9638,7 +9638,7 @@ var require_compile2 = __commonJS({
9638
9638
  function sameSchemaEnv(s1, s2) {
9639
9639
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
9640
9640
  }
9641
- function resolve14(root, ref) {
9641
+ function resolve15(root, ref) {
9642
9642
  let sch;
9643
9643
  while (typeof (sch = this.refs[ref]) == "string")
9644
9644
  ref = sch;
@@ -13270,7 +13270,7 @@ var require_src = __commonJS({
13270
13270
  // ../node_modules/depd/index.js
13271
13271
  var require_depd = __commonJS({
13272
13272
  "../node_modules/depd/index.js"(exports, module) {
13273
- var relative = __require("path").relative;
13273
+ var relative2 = __require("path").relative;
13274
13274
  module.exports = depd;
13275
13275
  var basePath = process.cwd();
13276
13276
  function containsNamespace(str2, namespace) {
@@ -13462,7 +13462,7 @@ var require_depd = __commonJS({
13462
13462
  return formatted;
13463
13463
  }
13464
13464
  function formatLocation(callSite) {
13465
- return relative(basePath, callSite[0]) + ":" + callSite[1] + ":" + callSite[2];
13465
+ return relative2(basePath, callSite[0]) + ":" + callSite[1] + ":" + callSite[2];
13466
13466
  }
13467
13467
  function getStack() {
13468
13468
  var limit = Error.stackTraceLimit;
@@ -17919,10 +17919,10 @@ var require_raw_body = __commonJS({
17919
17919
  if (done) {
17920
17920
  return readStream(stream, encoding, length, limit, wrap(done));
17921
17921
  }
17922
- return new Promise(function executor(resolve14, reject) {
17922
+ return new Promise(function executor(resolve15, reject) {
17923
17923
  readStream(stream, encoding, length, limit, function onRead(err, buf) {
17924
17924
  if (err) return reject(err);
17925
- resolve14(buf);
17925
+ resolve15(buf);
17926
17926
  });
17927
17927
  });
17928
17928
  }
@@ -27905,7 +27905,7 @@ var require_type_is = __commonJS({
27905
27905
  module.exports = typeofrequest;
27906
27906
  module.exports.is = typeis;
27907
27907
  module.exports.hasBody = hasbody;
27908
- module.exports.normalize = normalize;
27908
+ module.exports.normalize = normalize2;
27909
27909
  module.exports.match = mimeMatch;
27910
27910
  function typeis(value, types_) {
27911
27911
  var i;
@@ -27925,7 +27925,7 @@ var require_type_is = __commonJS({
27925
27925
  }
27926
27926
  var type2;
27927
27927
  for (i = 0; i < types.length; i++) {
27928
- if (mimeMatch(normalize(type2 = types[i]), val)) {
27928
+ if (mimeMatch(normalize2(type2 = types[i]), val)) {
27929
27929
  return type2[0] === "+" || type2.indexOf("*") !== -1 ? val : type2;
27930
27930
  }
27931
27931
  }
@@ -27940,7 +27940,7 @@ var require_type_is = __commonJS({
27940
27940
  var value = req.headers["content-type"];
27941
27941
  return typeis(value, types);
27942
27942
  }
27943
- function normalize(type2) {
27943
+ function normalize2(type2) {
27944
27944
  if (typeof type2 !== "string") {
27945
27945
  return false;
27946
27946
  }
@@ -31258,7 +31258,7 @@ var require_view = __commonJS({
31258
31258
  var basename8 = path4.basename;
31259
31259
  var extname3 = path4.extname;
31260
31260
  var join19 = path4.join;
31261
- var resolve14 = path4.resolve;
31261
+ var resolve15 = path4.resolve;
31262
31262
  module.exports = View;
31263
31263
  function View(name, options) {
31264
31264
  var opts = options || {};
@@ -31292,7 +31292,7 @@ var require_view = __commonJS({
31292
31292
  debug('lookup "%s"', name);
31293
31293
  for (var i = 0; i < roots.length && !path5; i++) {
31294
31294
  var root = roots[i];
31295
- var loc = resolve14(root, name);
31295
+ var loc = resolve15(root, name);
31296
31296
  var dir = dirname8(loc);
31297
31297
  var file = basename8(loc);
31298
31298
  path5 = this.resolve(dir, file);
@@ -31317,7 +31317,7 @@ var require_view = __commonJS({
31317
31317
  });
31318
31318
  sync = false;
31319
31319
  };
31320
- View.prototype.resolve = function resolve15(dir, file) {
31320
+ View.prototype.resolve = function resolve16(dir, file) {
31321
31321
  var ext = this.ext;
31322
31322
  var path5 = join19(dir, file);
31323
31323
  var stat = tryStat(path5);
@@ -33458,7 +33458,7 @@ var require_application = __commonJS({
33458
33458
  var compileETag = require_utils4().compileETag;
33459
33459
  var compileQueryParser = require_utils4().compileQueryParser;
33460
33460
  var compileTrust = require_utils4().compileTrust;
33461
- var resolve14 = __require("node:path").resolve;
33461
+ var resolve15 = __require("node:path").resolve;
33462
33462
  var once = require_once();
33463
33463
  var Router = require_router();
33464
33464
  var slice = Array.prototype.slice;
@@ -33512,7 +33512,7 @@ var require_application = __commonJS({
33512
33512
  this.mountpath = "/";
33513
33513
  this.locals.settings = this.settings;
33514
33514
  this.set("view", View);
33515
- this.set("views", resolve14("views"));
33515
+ this.set("views", resolve15("views"));
33516
33516
  this.set("jsonp callback name", "callback");
33517
33517
  if (env === "production") {
33518
33518
  this.enable("view cache");
@@ -34970,9 +34970,9 @@ var require_send = __commonJS({
34970
34970
  var util2 = __require("util");
34971
34971
  var extname3 = path4.extname;
34972
34972
  var join19 = path4.join;
34973
- var normalize = path4.normalize;
34974
- var resolve14 = path4.resolve;
34975
- var sep2 = path4.sep;
34973
+ var normalize2 = path4.normalize;
34974
+ var resolve15 = path4.resolve;
34975
+ var sep3 = path4.sep;
34976
34976
  var BYTES_RANGE_REGEXP = /^ *bytes=/;
34977
34977
  var MAX_MAXAGE = 60 * 60 * 24 * 365 * 1e3;
34978
34978
  var UP_PATH_REGEXP = /(?:^|[\\/])\.\.(?:[\\/]|$)/;
@@ -35000,7 +35000,7 @@ var require_send = __commonJS({
35000
35000
  this._maxage = opts.maxAge || opts.maxage;
35001
35001
  this._maxage = typeof this._maxage === "string" ? ms(this._maxage) : Number(this._maxage);
35002
35002
  this._maxage = !isNaN(this._maxage) ? Math.min(Math.max(0, this._maxage), MAX_MAXAGE) : 0;
35003
- this._root = opts.root ? resolve14(opts.root) : null;
35003
+ this._root = opts.root ? resolve15(opts.root) : null;
35004
35004
  }
35005
35005
  util2.inherits(SendStream, Stream);
35006
35006
  SendStream.prototype.error = function error2(status, err) {
@@ -35133,23 +35133,23 @@ var require_send = __commonJS({
35133
35133
  var parts;
35134
35134
  if (root !== null) {
35135
35135
  if (path5) {
35136
- path5 = normalize("." + sep2 + path5);
35136
+ path5 = normalize2("." + sep3 + path5);
35137
35137
  }
35138
35138
  if (UP_PATH_REGEXP.test(path5)) {
35139
35139
  debug('malicious path "%s"', path5);
35140
35140
  this.error(403);
35141
35141
  return res;
35142
35142
  }
35143
- parts = path5.split(sep2);
35144
- path5 = normalize(join19(root, path5));
35143
+ parts = path5.split(sep3);
35144
+ path5 = normalize2(join19(root, path5));
35145
35145
  } else {
35146
35146
  if (UP_PATH_REGEXP.test(path5)) {
35147
35147
  debug('malicious path "%s"', path5);
35148
35148
  this.error(403);
35149
35149
  return res;
35150
35150
  }
35151
- parts = normalize(path5).split(sep2);
35152
- path5 = resolve14(path5);
35151
+ parts = normalize2(path5).split(sep3);
35152
+ path5 = resolve15(path5);
35153
35153
  }
35154
35154
  if (containsDotFile(parts)) {
35155
35155
  debug('%s dotfile "%s"', this._dotfiles, path5);
@@ -35242,7 +35242,7 @@ var require_send = __commonJS({
35242
35242
  var self = this;
35243
35243
  debug('stat "%s"', path5);
35244
35244
  fs3.stat(path5, function onstat(err, stat) {
35245
- var pathEndsWithSep = path5[path5.length - 1] === sep2;
35245
+ var pathEndsWithSep = path5[path5.length - 1] === sep3;
35246
35246
  if (err && err.code === "ENOENT" && !extname3(path5) && !pathEndsWithSep) {
35247
35247
  return next(err);
35248
35248
  }
@@ -35527,7 +35527,7 @@ var require_response = __commonJS({
35527
35527
  var cookie = require_cookie();
35528
35528
  var send = require_send();
35529
35529
  var extname3 = path4.extname;
35530
- var resolve14 = path4.resolve;
35530
+ var resolve15 = path4.resolve;
35531
35531
  var vary = require_vary();
35532
35532
  var { Buffer: Buffer2 } = __require("node:buffer");
35533
35533
  var res = Object.create(http.ServerResponse.prototype);
@@ -35733,7 +35733,7 @@ var require_response = __commonJS({
35733
35733
  }
35734
35734
  opts = Object.create(opts);
35735
35735
  opts.headers = headers;
35736
- var fullPath = !opts.root ? resolve14(path5) : path5;
35736
+ var fullPath = !opts.root ? resolve15(path5) : path5;
35737
35737
  return this.sendFile(fullPath, opts, done);
35738
35738
  };
35739
35739
  res.contentType = res.type = function contentType(type2) {
@@ -35982,7 +35982,7 @@ var require_serve_static = __commonJS({
35982
35982
  var encodeUrl = require_encodeurl();
35983
35983
  var escapeHtml = require_escape_html();
35984
35984
  var parseUrl = require_parseurl();
35985
- var resolve14 = __require("path").resolve;
35985
+ var resolve15 = __require("path").resolve;
35986
35986
  var send = require_send();
35987
35987
  var url = __require("url");
35988
35988
  module.exports = serveStatic;
@@ -36001,7 +36001,7 @@ var require_serve_static = __commonJS({
36001
36001
  throw new TypeError("option setHeaders must be function");
36002
36002
  }
36003
36003
  opts.maxage = opts.maxage || opts.maxAge || 0;
36004
- opts.root = resolve14(root);
36004
+ opts.root = resolve15(root);
36005
36005
  var onDirectory = redirect ? createRedirectDirectoryListener() : createNotFoundDirectoryListener();
36006
36006
  return function serveStatic2(req, res, next) {
36007
36007
  if (req.method !== "GET" && req.method !== "HEAD") {
@@ -36695,8 +36695,8 @@ var require_main = __commonJS({
36695
36695
  const shortPaths = [];
36696
36696
  for (const filePath of optionPaths) {
36697
36697
  try {
36698
- const relative = path4.relative(process.cwd(), filePath);
36699
- shortPaths.push(relative);
36698
+ const relative2 = path4.relative(process.cwd(), filePath);
36699
+ shortPaths.push(relative2);
36700
36700
  } catch (e) {
36701
36701
  if (debug) {
36702
36702
  _debug(`Failed to load ${filePath} ${e.message}`);
@@ -36992,7 +36992,7 @@ var init_temp_dir = __esm({
36992
36992
  import { clearTimeout as clearTimeout2, setTimeout as setTimeout2 } from "timers";
36993
36993
  function waitForProcessReady(child, name, opts) {
36994
36994
  const timeoutMs = opts?.timeoutMs ?? DEFAULT_READY_TIMEOUT_MS;
36995
- return new Promise((resolve14, reject) => {
36995
+ return new Promise((resolve15, reject) => {
36996
36996
  let settled = false;
36997
36997
  const cleanup = () => {
36998
36998
  settled = true;
@@ -37006,13 +37006,13 @@ function waitForProcessReady(child, name, opts) {
37006
37006
  if (settled) return;
37007
37007
  logger.debug(`${name}: ready (stderr output detected)`);
37008
37008
  cleanup();
37009
- resolve14();
37009
+ resolve15();
37010
37010
  };
37011
37011
  const onStdout = () => {
37012
37012
  if (settled) return;
37013
37013
  logger.debug(`${name}: ready (stdout output detected)`);
37014
37014
  cleanup();
37015
- resolve14();
37015
+ resolve15();
37016
37016
  };
37017
37017
  const onError = (error2) => {
37018
37018
  if (settled) return;
@@ -37028,7 +37028,7 @@ function waitForProcessReady(child, name, opts) {
37028
37028
  if (settled) return;
37029
37029
  logger.warn(`${name}: readiness timeout (${timeoutMs} ms) \u2014 proceeding anyway`);
37030
37030
  cleanup();
37031
- resolve14();
37031
+ resolve15();
37032
37032
  }, timeoutMs);
37033
37033
  child.stderr?.on("data", onStderr);
37034
37034
  child.stdout?.on("data", onStdout);
@@ -37196,7 +37196,7 @@ var init_language_server = __esm({
37196
37196
  method,
37197
37197
  params
37198
37198
  };
37199
- return new Promise((resolve14, reject) => {
37199
+ return new Promise((resolve15, reject) => {
37200
37200
  const timer = setTimeout3(() => {
37201
37201
  if (this.pendingResponses.has(id)) {
37202
37202
  this.pendingResponses.delete(id);
@@ -37210,7 +37210,7 @@ var init_language_server = __esm({
37210
37210
  },
37211
37211
  resolve: (val) => {
37212
37212
  clearTimeout3(timer);
37213
- resolve14(val);
37213
+ resolve15(val);
37214
37214
  }
37215
37215
  });
37216
37216
  this.sendMessage(message);
@@ -37299,7 +37299,7 @@ var init_language_server = __esm({
37299
37299
  throw new Error("Language server is not initialized");
37300
37300
  }
37301
37301
  const documentUri = uri || pathToFileURL(join2(getProjectTmpDir("lsp-eval"), "eval.ql")).href;
37302
- return new Promise((resolve14, reject) => {
37302
+ return new Promise((resolve15, reject) => {
37303
37303
  let diagnosticsReceived = false;
37304
37304
  const timeout = setTimeout3(() => {
37305
37305
  if (!diagnosticsReceived) {
@@ -37315,7 +37315,7 @@ var init_language_server = __esm({
37315
37315
  this.sendNotification("textDocument/didClose", {
37316
37316
  textDocument: { uri: documentUri }
37317
37317
  });
37318
- resolve14(params.diagnostics);
37318
+ resolve15(params.diagnostics);
37319
37319
  }
37320
37320
  };
37321
37321
  this.on("diagnostics", diagnosticsHandler);
@@ -37375,6 +37375,28 @@ var init_language_server = __esm({
37375
37375
  });
37376
37376
  return this.normalizeLocations(result);
37377
37377
  }
37378
+ /**
37379
+ * Get document symbols (i.e. top-level declarations) for a file.
37380
+ * Returns a hierarchical DocumentSymbol[] when the server supports it, or a
37381
+ * flat SymbolInformation[] otherwise. Top-level symbols are the root nodes
37382
+ * of the returned array.
37383
+ */
37384
+ async getDocumentSymbols(params) {
37385
+ if (!this.isInitialized) {
37386
+ throw new Error("Language server is not initialized");
37387
+ }
37388
+ if (!this.isRunning()) {
37389
+ throw new Error("Language server process is not running");
37390
+ }
37391
+ const result = await this.sendRequest("textDocument/documentSymbol", params);
37392
+ if (!result || !Array.isArray(result) || result.length === 0) {
37393
+ return [];
37394
+ }
37395
+ if ("selectionRange" in result[0]) {
37396
+ return result;
37397
+ }
37398
+ return result;
37399
+ }
37378
37400
  /**
37379
37401
  * Open a text document in the language server.
37380
37402
  * The document must be opened before requesting completions, definitions, etc.
@@ -37430,22 +37452,22 @@ var init_language_server = __esm({
37430
37452
  } catch (error2) {
37431
37453
  logger.warn("Error during graceful shutdown:", error2);
37432
37454
  }
37433
- await new Promise((resolve14) => {
37455
+ await new Promise((resolve15) => {
37434
37456
  const timer = setTimeout3(() => {
37435
37457
  if (this.server) {
37436
37458
  this.server.kill("SIGTERM");
37437
37459
  }
37438
- resolve14();
37460
+ resolve15();
37439
37461
  }, 1e3);
37440
37462
  if (this.server) {
37441
37463
  this.server.once("exit", () => {
37442
37464
  clearTimeout3(timer);
37443
37465
  this.server = null;
37444
- resolve14();
37466
+ resolve15();
37445
37467
  });
37446
37468
  } else {
37447
37469
  clearTimeout3(timer);
37448
- resolve14();
37470
+ resolve15();
37449
37471
  }
37450
37472
  });
37451
37473
  this.isInitialized = false;
@@ -37535,8 +37557,8 @@ var init_query_server = __esm({
37535
37557
  method,
37536
37558
  params
37537
37559
  };
37538
- return new Promise((resolve14, reject) => {
37539
- this.pendingRequests.set(id, { reject, resolve: resolve14 });
37560
+ return new Promise((resolve15, reject) => {
37561
+ this.pendingRequests.set(id, { reject, resolve: resolve15 });
37540
37562
  try {
37541
37563
  this.sendRaw(message);
37542
37564
  } catch (error2) {
@@ -37550,7 +37572,7 @@ var init_query_server = __esm({
37550
37572
  reject(new Error(`Query server request timeout for method: ${method}`));
37551
37573
  }
37552
37574
  }, timeoutMs);
37553
- const originalResolve = resolve14;
37575
+ const originalResolve = resolve15;
37554
37576
  const originalReject = reject;
37555
37577
  const wrapped = {
37556
37578
  reject: (err) => {
@@ -37578,23 +37600,23 @@ var init_query_server = __esm({
37578
37600
  } catch (error2) {
37579
37601
  logger.warn("Error during query server graceful shutdown:", error2);
37580
37602
  }
37581
- await new Promise((resolve14) => {
37603
+ await new Promise((resolve15) => {
37582
37604
  const timer = setTimeout4(() => {
37583
37605
  if (this.process) {
37584
37606
  this.process.kill("SIGTERM");
37585
37607
  this.process = null;
37586
37608
  }
37587
- resolve14();
37609
+ resolve15();
37588
37610
  }, 2e3);
37589
37611
  if (this.process) {
37590
37612
  this.process.once("exit", () => {
37591
37613
  clearTimeout4(timer);
37592
37614
  this.process = null;
37593
- resolve14();
37615
+ resolve15();
37594
37616
  });
37595
37617
  } else {
37596
37618
  clearTimeout4(timer);
37597
- resolve14();
37619
+ resolve15();
37598
37620
  }
37599
37621
  });
37600
37622
  }
@@ -37755,9 +37777,9 @@ var init_cli_server = __esm({
37755
37777
  * @returns The stdout output from the command.
37756
37778
  */
37757
37779
  runCommand(args) {
37758
- return new Promise((resolve14, reject) => {
37780
+ return new Promise((resolve15, reject) => {
37759
37781
  const execute = () => {
37760
- this.executeCommand({ args, reject, resolve: resolve14 });
37782
+ this.executeCommand({ args, reject, resolve: resolve15 });
37761
37783
  };
37762
37784
  if (this.commandInProgress) {
37763
37785
  this.commandQueue.push(execute);
@@ -37780,23 +37802,23 @@ var init_cli_server = __esm({
37780
37802
  } catch (error2) {
37781
37803
  logger.warn("Error during CLI server shutdown request:", error2);
37782
37804
  }
37783
- await new Promise((resolve14) => {
37805
+ await new Promise((resolve15) => {
37784
37806
  const timer = setTimeout5(() => {
37785
37807
  if (this.process) {
37786
37808
  this.process.kill("SIGTERM");
37787
37809
  this.process = null;
37788
37810
  }
37789
- resolve14();
37811
+ resolve15();
37790
37812
  }, 2e3);
37791
37813
  if (this.process) {
37792
37814
  this.process.once("exit", () => {
37793
37815
  clearTimeout5(timer);
37794
37816
  this.process = null;
37795
- resolve14();
37817
+ resolve15();
37796
37818
  });
37797
37819
  } else {
37798
37820
  clearTimeout5(timer);
37799
- resolve14();
37821
+ resolve15();
37800
37822
  }
37801
37823
  });
37802
37824
  this.commandInProgress = false;
@@ -38041,11 +38063,11 @@ var init_server_manager = __esm({
38041
38063
  async warmUpLanguageServer() {
38042
38064
  try {
38043
38065
  const { packageRootDir: packageRootDir2 } = await Promise.resolve().then(() => (init_package_paths(), package_paths_exports));
38044
- const { resolve: resolve14 } = await import("path");
38066
+ const { resolve: resolve15 } = await import("path");
38045
38067
  const config2 = {
38046
38068
  checkErrors: "ON_CHANGE",
38047
38069
  loglevel: "WARN",
38048
- searchPath: resolve14(packageRootDir2, "ql")
38070
+ searchPath: resolve15(packageRootDir2, "ql")
38049
38071
  };
38050
38072
  logger.info("Warming up language server (background JVM start)...");
38051
38073
  await this.getLanguageServer(config2);
@@ -40527,8 +40549,8 @@ var require_adm_zip = __commonJS({
40527
40549
  return null;
40528
40550
  }
40529
40551
  function fixPath(zipPath) {
40530
- const { join: join19, normalize, sep: sep2 } = pth.posix;
40531
- return join19(".", normalize(sep2 + zipPath.split("\\").join(sep2) + sep2));
40552
+ const { join: join19, normalize: normalize2, sep: sep3 } = pth.posix;
40553
+ return join19(".", normalize2(sep3 + zipPath.split("\\").join(sep3) + sep3));
40532
40554
  }
40533
40555
  function filenameFilter(filterfn) {
40534
40556
  if (filterfn instanceof RegExp) {
@@ -40923,10 +40945,10 @@ var require_adm_zip = __commonJS({
40923
40945
  * @param {function|string} [props.namefix] - optional function to help fix filename
40924
40946
  */
40925
40947
  addLocalFolderPromise: function(localPath2, props) {
40926
- return new Promise((resolve14, reject) => {
40948
+ return new Promise((resolve15, reject) => {
40927
40949
  this.addLocalFolderAsync2(Object.assign({ localPath: localPath2 }, props), (err, done) => {
40928
40950
  if (err) reject(err);
40929
- if (done) resolve14(this);
40951
+ if (done) resolve15(this);
40930
40952
  });
40931
40953
  });
40932
40954
  },
@@ -41113,12 +41135,12 @@ var require_adm_zip = __commonJS({
41113
41135
  keepOriginalPermission = get_Bool(false, keepOriginalPermission);
41114
41136
  overwrite = get_Bool(false, overwrite);
41115
41137
  if (!callback) {
41116
- return new Promise((resolve14, reject) => {
41138
+ return new Promise((resolve15, reject) => {
41117
41139
  this.extractAllToAsync(targetPath, overwrite, keepOriginalPermission, function(err) {
41118
41140
  if (err) {
41119
41141
  reject(err);
41120
41142
  } else {
41121
- resolve14(this);
41143
+ resolve15(this);
41122
41144
  }
41123
41145
  });
41124
41146
  });
@@ -41216,11 +41238,11 @@ var require_adm_zip = __commonJS({
41216
41238
  */
41217
41239
  writeZipPromise: function(targetFileName, props) {
41218
41240
  const { overwrite, perm } = Object.assign({ overwrite: true }, props);
41219
- return new Promise((resolve14, reject) => {
41241
+ return new Promise((resolve15, reject) => {
41220
41242
  if (!targetFileName && opts.filename) targetFileName = opts.filename;
41221
41243
  if (!targetFileName) reject("ADM-ZIP: ZIP File Name Missing");
41222
41244
  this.toBufferPromise().then((zipData) => {
41223
- const ret = (done) => done ? resolve14(done) : reject("ADM-ZIP: Wasn't able to write zip file");
41245
+ const ret = (done) => done ? resolve15(done) : reject("ADM-ZIP: Wasn't able to write zip file");
41224
41246
  filetools.writeFileToAsync(targetFileName, zipData, overwrite, perm, ret);
41225
41247
  }, reject);
41226
41248
  });
@@ -41229,8 +41251,8 @@ var require_adm_zip = __commonJS({
41229
41251
  * @returns {Promise<Buffer>} A promise to the Buffer.
41230
41252
  */
41231
41253
  toBufferPromise: function() {
41232
- return new Promise((resolve14, reject) => {
41233
- _zip.toAsyncBuffer(resolve14, reject);
41254
+ return new Promise((resolve15, reject) => {
41255
+ _zip.toAsyncBuffer(resolve15, reject);
41234
41256
  });
41235
41257
  },
41236
41258
  /**
@@ -53328,7 +53350,7 @@ var Protocol = class {
53328
53350
  return;
53329
53351
  }
53330
53352
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
53331
- await new Promise((resolve14) => setTimeout(resolve14, pollInterval));
53353
+ await new Promise((resolve15) => setTimeout(resolve15, pollInterval));
53332
53354
  options?.signal?.throwIfAborted();
53333
53355
  }
53334
53356
  } catch (error2) {
@@ -53345,7 +53367,7 @@ var Protocol = class {
53345
53367
  */
53346
53368
  request(request, resultSchema, options) {
53347
53369
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
53348
- return new Promise((resolve14, reject) => {
53370
+ return new Promise((resolve15, reject) => {
53349
53371
  const earlyReject = (error2) => {
53350
53372
  reject(error2);
53351
53373
  };
@@ -53423,7 +53445,7 @@ var Protocol = class {
53423
53445
  if (!parseResult.success) {
53424
53446
  reject(parseResult.error);
53425
53447
  } else {
53426
- resolve14(parseResult.data);
53448
+ resolve15(parseResult.data);
53427
53449
  }
53428
53450
  } catch (error2) {
53429
53451
  reject(error2);
@@ -53684,12 +53706,12 @@ var Protocol = class {
53684
53706
  }
53685
53707
  } catch {
53686
53708
  }
53687
- return new Promise((resolve14, reject) => {
53709
+ return new Promise((resolve15, reject) => {
53688
53710
  if (signal.aborted) {
53689
53711
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
53690
53712
  return;
53691
53713
  }
53692
- const timeoutId = setTimeout(resolve14, interval);
53714
+ const timeoutId = setTimeout(resolve15, interval);
53693
53715
  signal.addEventListener("abort", () => {
53694
53716
  clearTimeout(timeoutId);
53695
53717
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -54789,7 +54811,7 @@ var McpServer = class {
54789
54811
  let task = createTaskResult.task;
54790
54812
  const pollInterval = task.pollInterval ?? 5e3;
54791
54813
  while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
54792
- await new Promise((resolve14) => setTimeout(resolve14, pollInterval));
54814
+ await new Promise((resolve15) => setTimeout(resolve15, pollInterval));
54793
54815
  const updatedTask = await extra.taskStore.getTask(taskId);
54794
54816
  if (!updatedTask) {
54795
54817
  throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
@@ -55432,12 +55454,12 @@ var StdioServerTransport = class {
55432
55454
  this.onclose?.();
55433
55455
  }
55434
55456
  send(message) {
55435
- return new Promise((resolve14) => {
55457
+ return new Promise((resolve15) => {
55436
55458
  const json2 = serializeMessage(message);
55437
55459
  if (this._stdout.write(json2)) {
55438
- resolve14();
55460
+ resolve15();
55439
55461
  } else {
55440
- this._stdout.once("drain", resolve14);
55462
+ this._stdout.once("drain", resolve15);
55441
55463
  }
55442
55464
  });
55443
55465
  }
@@ -55870,7 +55892,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
55870
55892
  });
55871
55893
  if (!chunk) {
55872
55894
  if (i === 1) {
55873
- await new Promise((resolve14) => setTimeout(resolve14));
55895
+ await new Promise((resolve15) => setTimeout(resolve15));
55874
55896
  maxReadCount = 3;
55875
55897
  continue;
55876
55898
  }
@@ -56366,9 +56388,9 @@ data:
56366
56388
  const initRequest = messages.find((m) => isInitializeRequest(m));
56367
56389
  const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
56368
56390
  if (this._enableJsonResponse) {
56369
- return new Promise((resolve14) => {
56391
+ return new Promise((resolve15) => {
56370
56392
  this._streamMapping.set(streamId, {
56371
- resolveJson: resolve14,
56393
+ resolveJson: resolve15,
56372
56394
  cleanup: () => {
56373
56395
  this._streamMapping.delete(streamId);
56374
56396
  }
@@ -56703,7 +56725,7 @@ var import_express = __toESM(require_express2(), 1);
56703
56725
  var import_cors = __toESM(require_lib3(), 1);
56704
56726
  var import_dotenv = __toESM(require_main(), 1);
56705
56727
  import { realpathSync as realpathSync2 } from "fs";
56706
- import { resolve as resolve13 } from "path";
56728
+ import { resolve as resolve14 } from "path";
56707
56729
  import { pathToFileURL as pathToFileURL5 } from "url";
56708
56730
 
56709
56731
  // src/lib/cli-tool-registry.ts
@@ -57272,6 +57294,11 @@ function registerCLITool(server, definition) {
57272
57294
  positionalArgs = [...positionalArgs, query];
57273
57295
  }
57274
57296
  break;
57297
+ case "codeql_resolve_library-path":
57298
+ if (query) {
57299
+ options.query = query;
57300
+ }
57301
+ break;
57275
57302
  case "codeql_resolve_queries":
57276
57303
  if (directory) {
57277
57304
  positionalArgs = [...positionalArgs, directory];
@@ -62790,19 +62817,19 @@ var codeqlResolveLanguagesTool = {
62790
62817
  // src/tools/codeql/resolve-library-path.ts
62791
62818
  var codeqlResolveLibraryPathTool = {
62792
62819
  name: "codeql_resolve_library-path",
62793
- description: "Resolve library path for CodeQL queries and libraries",
62820
+ description: "Resolve paths to source code for all libraries used by, or available to, the given CodeQL query or qll file.",
62794
62821
  command: "codeql",
62795
62822
  subcommand: "resolve library-path",
62796
62823
  inputSchema: {
62797
- language: external_exports.string().optional().describe("Programming language to resolve library path for"),
62824
+ query: external_exports.string().describe("Path to a .ql or .qll file for the context to perform resolution for."),
62798
62825
  format: external_exports.enum(["text", "json", "betterjson"]).optional().describe("Output format for library path information"),
62799
62826
  verbose: external_exports.boolean().optional().describe("Enable verbose output"),
62800
62827
  additionalArgs: external_exports.array(external_exports.string()).optional().describe("Additional command-line arguments")
62801
62828
  },
62802
62829
  examples: [
62803
- "codeql resolve library-path --language=java",
62804
- "codeql resolve library-path --format=json --language=python",
62805
- "codeql resolve library-path --format=betterjson"
62830
+ "codeql resolve library-path --query=/path/to/query.ql",
62831
+ "codeql resolve library-path --format=json --query=/path/to/query.ql",
62832
+ "codeql resolve library-path --format=betterjson --query=/path/to/query.ql"
62806
62833
  ],
62807
62834
  resultProcessor: defaultCLIResultProcessor
62808
62835
  };
@@ -62826,6 +62853,24 @@ var codeqlResolveMetadataTool = {
62826
62853
  resultProcessor: defaultCLIResultProcessor
62827
62854
  };
62828
62855
 
62856
+ // src/tools/codeql/resolve-packs.ts
62857
+ var codeqlResolvePacksTool = {
62858
+ name: "codeql_resolve_packs",
62859
+ description: "Resolve packs available within a project directory, provided as a search path, and the source roots of those available packs.",
62860
+ command: "codeql",
62861
+ subcommand: "resolve packs",
62862
+ inputSchema: {
62863
+ "search-path": external_exports.string().describe('The project root, to search packs available in the project. Typically the ".", or the current working directory.'),
62864
+ format: external_exports.enum(["text", "json", "betterjson"]).optional().describe("Output format for qlref resolution"),
62865
+ verbose: createCodeQLSchemas.verbose(),
62866
+ additionalArgs: createCodeQLSchemas.additionalArgs()
62867
+ },
62868
+ examples: [
62869
+ "codeql resolve packs --search-path=."
62870
+ ],
62871
+ resultProcessor: defaultCLIResultProcessor
62872
+ };
62873
+
62829
62874
  // src/tools/codeql/resolve-qlref.ts
62830
62875
  var codeqlResolveQlrefTool = {
62831
62876
  name: "codeql_resolve_qlref",
@@ -63435,6 +63480,7 @@ function registerCodeQLTools(server) {
63435
63480
  registerCLITool(server, codeqlResolveLanguagesTool);
63436
63481
  registerCLITool(server, codeqlResolveLibraryPathTool);
63437
63482
  registerCLITool(server, codeqlResolveMetadataTool);
63483
+ registerCLITool(server, codeqlResolvePacksTool);
63438
63484
  registerCLITool(server, codeqlResolveQlrefTool);
63439
63485
  registerCLITool(server, codeqlResolveQueriesTool);
63440
63486
  registerCLITool(server, codeqlResolveTestsTool);
@@ -63967,6 +64013,39 @@ async function lspReferences(params) {
63967
64013
  server.closeDocument(docUri);
63968
64014
  }
63969
64015
  }
64016
+ async function lspDocumentSymbols(params) {
64017
+ logger.info(`LSP documentSymbol for ${params.filePath}`);
64018
+ const server = await getInitializedLanguageServer({
64019
+ serverOptions: { searchPath: params.searchPath },
64020
+ workspaceUri: params.workspaceUri
64021
+ });
64022
+ const paramsWithPosition = {
64023
+ character: 0,
64024
+ line: 0,
64025
+ ...params
64026
+ };
64027
+ const { absPath, docUri } = prepareDocumentPosition(paramsWithPosition);
64028
+ await openDocumentForPosition(server, paramsWithPosition, absPath, docUri);
64029
+ try {
64030
+ return await server.getDocumentSymbols({ textDocument: { uri: docUri } });
64031
+ } finally {
64032
+ server.closeDocument(docUri);
64033
+ }
64034
+ }
64035
+ function extractNamesFromDocumentSymbols(symbols) {
64036
+ let symbolNames = [];
64037
+ function collectSymbolNames(symbols2) {
64038
+ symbols2.forEach((s) => {
64039
+ const sym = s;
64040
+ symbolNames.push(sym.name ?? "(unknown)");
64041
+ if ("children" in sym && Array.isArray(sym.children)) {
64042
+ collectSymbolNames(sym.children);
64043
+ }
64044
+ });
64045
+ }
64046
+ collectSymbolNames(symbols);
64047
+ return symbolNames;
64048
+ }
63970
64049
 
63971
64050
  // src/tools/lsp/lsp-tools.ts
63972
64051
  init_logger();
@@ -63988,6 +64067,12 @@ function toHandlerParams(input) {
63988
64067
  workspaceUri: input.workspace_uri
63989
64068
  };
63990
64069
  }
64070
+ var lspFileParamsSchema = {
64071
+ file_content: external_exports.string().optional().describe("Optional file content override (reads from disk if omitted)"),
64072
+ file_path: external_exports.string().describe("Path to the CodeQL (.ql/.qll) file. Relative paths are resolved against the user workspace directory (see CODEQL_MCP_WORKSPACE)."),
64073
+ search_path: external_exports.string().optional().describe("Optional search path for CodeQL libraries"),
64074
+ workspace_uri: external_exports.string().optional().describe("Optional workspace URI for context (defaults to ./ql directory)")
64075
+ };
63991
64076
  function registerLSPTools(server) {
63992
64077
  registerLspDiagnosticsTool(server);
63993
64078
  server.tool(
@@ -64083,6 +64168,42 @@ function registerLSPTools(server) {
64083
64168
  }
64084
64169
  }
64085
64170
  );
64171
+ server.tool(
64172
+ "codeql_lsp_document_symbols",
64173
+ "List all top-level definitions (classes, predicates, modules) in a CodeQL file. Response contains location and type information unless names_only is set to true.",
64174
+ {
64175
+ names_only: external_exports.boolean().optional().describe("If true, returns only symbol names as a compact string array instead of full symbol objects. Use this when you only need to know what names a file defines."),
64176
+ ...lspFileParamsSchema
64177
+ },
64178
+ async (input) => {
64179
+ try {
64180
+ const symbols = await lspDocumentSymbols({
64181
+ fileContent: input.file_content,
64182
+ filePath: input.file_path,
64183
+ searchPath: input.search_path,
64184
+ workspaceUri: input.workspace_uri
64185
+ });
64186
+ let result;
64187
+ if (input.names_only) {
64188
+ result = extractNamesFromDocumentSymbols(symbols);
64189
+ } else {
64190
+ result = symbols;
64191
+ }
64192
+ return {
64193
+ content: [{
64194
+ text: JSON.stringify({ symbolCount: result.length, symbols: result }, null, 2),
64195
+ type: "text"
64196
+ }]
64197
+ };
64198
+ } catch (error2) {
64199
+ logger.error("codeql_lsp_document_symbols error:", error2);
64200
+ return {
64201
+ content: [{ text: `Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`, type: "text" }],
64202
+ isError: true
64203
+ };
64204
+ }
64205
+ }
64206
+ );
64086
64207
  }
64087
64208
 
64088
64209
  // src/resources/languages/actions_ast.md
@@ -64257,7 +64378,12 @@ function registerLanguageResources(server) {
64257
64378
  }
64258
64379
 
64259
64380
  // src/prompts/workflow-prompts.ts
64260
- import { basename as basename7 } from "path";
64381
+ import { access as access2 } from "fs/promises";
64382
+ import { basename as basename7, isAbsolute as isAbsolute7, normalize, relative, resolve as resolve13, sep as sep2 } from "path";
64383
+ import { fileURLToPath as fileURLToPath3 } from "url";
64384
+
64385
+ // src/prompts/check-for-duplicated-code.prompt.md
64386
+ var check_for_duplicated_code_prompt_default = '---\nagent: agent\n---\n\n# Check for Duplicated Code\n\nUse the MCP server tools to identify classes, modules, and predicates defined in a\n`.ql` or `.qll` file and check for possible "duplicated code," where duplicated code\nis defined to be:\n\n- Reimplementing functionality that already exists in the standard library, or shared project `.qll` files, and\n- The local definition is identical, or semantically equivalent, or superior to the library definition, or\n- The local definition could be simplified by reusing the existing definition (e.g. a base class already exists that captures some of the shared logic)\n\nHere are some examples:\n\n```ql\nimport cpp\n\n// Duplicated: `StandardNamespace` already exists in the standard library and is identical\nclass NamespaceStd extends Namespace {\n NamespaceStd() { this.getName() = "std" }\n}\n\n// Duplicated: class should extend `Operator`, not `Function`\nclass ThrowingOperator extends Function {\n ThrowingOperator() {\n // Duplicated: this check is implied by using base class `Operator`\n this.getName().matches("%operator%") and\n and exists(ThrowExpr te |\n // Duplicated: this is equivalent to `te.getEnclosingFunction() = this`\n te.getParent*() = this.getAChild()\n )\n }\n\n // Duplicated: member predicate `getDeclaringType()` already does this.\n Class getDefiningClass() { ... }\n}\n\n// Duplicated: `ControlFlowNode.getASuccessor()` already exists in `cpp` and is superior\npredicate getASuccessor(Stmt a, Stmt b) {\n exists(Block b, int i | a = b.getChild(i) and b = b.getChild(i + 1))\n}\n\n// Duplicated: prefer to import `semmle.code.cpp.controlflow.Dominance`, defined in dependency pack `cpp-all`\npredicate dominates(Block a, Block b) { ... }\n```\n\nDuplicate code removal isn\'t done arbitrarily, but for several key reasons:\n\n- **Maintainability**: Duplicated code must be maintained separately, may diverge and have different bugs\n- **Simplicity**: Relying on existing definitions reduces the amount of code to read and understand\n- **Readability**: Existing definitions map wrap complex ideas into readable names\n- **Consistency**: A single source of truth makes for a more consistent user experience across queries\n- **Completeness/Correctness**: Recreating an already-existing definition can miss edge cases, resulting in false positives or false negatives\n\n## Use This Prompt When\n\n- A query file defines a class or predicate whose name sounds generic (e.g.\n `StandardNamespace`, `Callable`, `SecurityFeature`)\n- Refactoring a query that was written before a relevant library predicate existed\n- Reviewing a shared `.qll` file to check whether its helpers have been upstreamed\n into the standard library in a newer CodeQL version\n- Performing a code-quality audit across a suite of custom queries\n\n## Prerequisites\n\n1. The file path of the `.ql` or `.qll` file to audit for code duplication\n2. Understand which packs are imported by `qlpack.yml`\n3. Understand where the relevant language library packs are located (e.g. `~/.codeql`)\n4. Understand where project-specific library packs are located (e.g. `$LANGUAGE/lib` or `$LANGUAGE/common`)\n5. Understand where pack-specific shared `.qll` files are located (e.g. `$PACKROOT/common/*.qll`)\n\n## Overview of the Approach\n\nThe core idea is to enumerate every top-level name defined in the file under review.\nThen, find candidate `.qll` files, based on file name and path, that are available to\nthat `.ql` file in review. Then, enumerate the top-level names in each candidate\n`.qll` file, to find potential duplicates, dive further if necessary, and then report\nthe findings as code improvement recommendations to the user.\n\n1. **Read the file** to see its imports and top-level structure\n2. **Enumerate top-level definitions** with `codeql_lsp_document_symbols`\n3. **Find available .qll files** in the `.ql` file\'s pack, and its dependencies, including the standard library\n4. **Identify promising .qll file candidates** based on their file name and path\n5. **Enumerate top-level definitions in candidate `.qll` files** with `codeql_lsp_document_symbols`\n6. **Detect overlap, comparing definitions if unclear** (e.g. by using `find_predicate_position` and `find_class_position` tools)\n7. **Report findings** as a set of recommendations to the user about which definitions could be improved, by reusing which existing definitions\n\n## Step 1: Read the File and Note Its Imports\n\n```text\nTool: read_file\nParameters:\n file_path: /path/to/query.ql\n start_line: 1\n end_line: 60 # enough to see all imports\n```\n\nRecord every `import` statement. These are the namespaces the standard library\nexposes; duplication is only meaningful for libraries that are already imported (or\neasily importable).\n\n## Step 2: Enumerate Top-Level Definitions\n\nUse `codeql_lsp_document_symbols` to retrieve every class, predicate, and module\ndefined at the top level of the file in a single call:\n\n```text\nTool: codeql_lsp_document_symbols\nParameters:\n file_path: /path/to/query.ql\n names_only: true # provides significantly smaller response payload\n workspace_uri: /path/to/pack-root # directory containing codeql-pack.yml\n```\n\nThe response contains a `symbols` array. Each entry has:\n\n- `name` \u2014 the identifier as written in source\n- `kind` \u2014 numeric SymbolKind (5 = Class, 12 = Function/predicate, 2 = Module, etc.)\n- `range` \u2014 the full definition range (0-based lines)\n- `selectionRange` \u2014 the range of just the name token\n- `children` \u2014 nested members (for classes and modules)\n\nTop-level symbols are the root nodes of the array; `children` hold member\npredicates and fields.\n\n## Step 3. Read the filesystem to find candidate library `.qll` files\n\nRun the tool `codeql_resolve_library-path` with the given ql query file to find where\nthe available library sources live.\n\nFor each source root, run `find $ROOT -name "*.qll"` to find all `.qll` files\navailable in that pack. Do not preemptively filter this list of qll files. The names\nof the files may be broad or nondescriptive. Read all file names for each project to\nunderstand its structure and responsibilities before proceeding to step 3d.\n\nChoose promising candidate `.qll` files you found in the previous step. Pick\ncandidates that may potentially define behavior relevant to the current query and its\nenumerated definitions, based on the candidate filename, path, and priority.\n\nPrioritize as follows:\n\n- `.qll` files in the same directory as the query file have the absolute highest priority\n- `.qll` files in the same pack have the next extremely high priority\n- `.qll` files in project-specific library packs have the very high priority\n- `.qll` files in downloaded direct dependencies have standard priority\n- `.qll` files in transitive dependencies have the least priority.\n\n## Step 4: Identify candidate terms in the candidate library `.qll` files\n\nEnumerate the top-level definitions for each candidate `.qll` file using the tool\n`codeql_lsp_document_symbols` again. Some top levels may clearly match the name or\npurpose of a definition in the query file, while others may only appear as possibly\nrelated.\n\n```text\nTool: codeql_lsp_document_symbols\nParameters:\n file_path: /path/to/library/file.qll\n workspace_uri: /path/to/pack-root\n```\n\n## Step 5: Perform final overlap analysis\n\nFor each promising candidate, identify the predicate or class definitions that may overlap. One definition will be in the query file (`.ql`) and the other will be in the library file (`.qll`).\n\nUsing the tools `find_predicate_position` and `find_class_position`, you can retrieve the full definition of each predicate or class, and compare them to determine whether they are identical, equivalent, overlapping, or if one is a superior implementation that could be reused by the query file.\n\nDutifully analyze whether the shared library file definition would reduce code duplication in the categories identified before: maintenance, simplicity, readability, consistency, and completeness/correctness. Consider contextual factors such as comments explaining why the local definition differs from the library one, or whether the local definition is a thin wrapper around the library definition that adds value (e.g. by improving naming or adding extra checks).\n\nDo not go on a wild goose chase trying to find every possible overlap. Consider the likelihood of overlap based on the broadness of functionality, and the value that would be brought be reuse. Do not waste significant time on unimportant or unlikely overlaps.\n\n## Step 6: Report Findings\n\nFor each duplicate found, report:\n\n| Local name | Local file | import path | Notes |\n| ------------------- | ------------- | -------------------------------- | ---------- |\n| `StandardNamespace` | `query.ql:42` | already imported in `import cpp` | Identical |\n| `myHelper` | `query.ql:80` | `import myproject.Helpers` | Equivalent |\n| `myHelper` | `query.ql:80` | `import myproject.Helpers` | Equivalent |\n\nRecommend one of:\n\n- **Replace**: remove the local definition and use the standard definition directly instead\n- **Integrate**: refactor and simplify the local definition by making use of the standard definition\n- **Annotate**: add comments to the local definition to explain how it differs from the standard definition and why the duplication is necessary\n\nAdditionally, report if any issues came up in using the tools, or finding the qll files.\n\nFor each concept for which no duplicate was found, provide at most a **brief** description of what the concept is. Do not provide a long detailed explanation of a non-finding.\n\n# Conclusion\n\nDo **not** perform any updates to any code during this analysis.\n\nAs you work through completing this task, ask yourself:\n\n- Have I changed any code, even though that was not my task, or am I about to? Stop, do not change any code!\n- Did I sufficiently analyze the definitions such that I likely found most overlapping definitions?\n- Will my suggestions improve the maintainability, simplicity, readability, consistency, or completeness/correctness of the codebase?\n- Did I report my findings clearly?\n- Did I use the suggested LLM tools to their fullest extent?\n- Did I follow the steps in the recommended order, and not skip any steps?\n- Did I report any issues I had in finding the relevant `.qll` files, or using the tools to analyze definitions?\n';
64261
64387
 
64262
64388
  // src/prompts/document-codeql-query.prompt.md
64263
64389
  var document_codeql_query_prompt_default = '---\nagent: agent\n---\n\n# Document a CodeQL Query\n\nThis prompt guides you through creating or updating documentation for a CodeQL query file. The documentation is stored as a sibling file to the query with a standardized markdown format.\n\n## Purpose\n\nThe `document_codeql_query` prompt creates/updates **query documentation files** for a specific version of a CodeQL query. Documentation files are stored alongside the query file and provide concise yet comprehensive information about what the query does.\n\nFor creating **workshop learning content** with detailed explanations and visual diagrams, use the `explain_codeql_query` prompt instead.\n\n## Required Inputs\n\n- **queryPath**: Path to the CodeQL query file (`.ql` or `.qlref`)\n- **language**: Target programming language (actions, cpp, csharp, go, java, javascript, python, ruby, swift)\n\n## Documentation File Conventions\n\n### File Location and Naming\n\nFor a query file `QueryFileBaseName.ql`, the documentation file should be:\n\n- **Primary**: `QueryFileBaseName.md` (markdown format, preferred)\n- **Legacy**: `QueryFileBaseName.qhelp` (XML-based query help format)\n\nDocumentation files are **siblings** to the query file (same directory).\n\n### Handling Existing Documentation\n\n1. **No documentation exists**: Create new `QueryFileBaseName.md` file\n2. **`.md` file exists**: Update the existing markdown file\n3. **`.qhelp` file exists**: Use #codeql_generate_query-help tool to convert to markdown, then update\n\n## Workflow Checklist\n\nUse the following MCP server tools to gather context before creating documentation:\n\n### Phase 1: Query Discovery\n\n- [ ] **Step 1: Locate query files**\n - Tool: #find_codeql_query_files\n - Parameters: `queryPath` = provided query path\n - Gather: Query source file path, existing documentation files, test files\n - Check: Does `QueryFileBaseName.md` or `QueryFileBaseName.qhelp` exist?\n\n- [ ] **Step 2: Read query metadata**\n - Tool: #codeql_resolve_metadata\n - Parameters: `query` = query file path\n - Gather: @name, @description, @kind, @id, @tags, @precision, @severity\n\n### Phase 2: Convert Existing qhelp (if needed)\n\n- [ ] **Step 3: Convert qhelp to markdown** (only if `.qhelp` exists)\n - Tool: #codeql_generate_query-help\n - Parameters: `query` = query file path, `format` = "markdown"\n - Use output as starting point for updated documentation\n\n### Phase 3: Gather Query Context\n\n- [ ] **Step 4: Validate query structure**\n - Tool: #validate_codeql_query\n - Parameters: `query` = query source code\n - Gather: Structural validation, suggestions\n - Note: This is a heuristic check only \u2014 for full validation, use #codeql_query_compile\n\n- [ ] **Step 5: Explore query types** (if deeper understanding needed)\n - Tool: #codeql_lsp_definition \u2014 navigate to class/predicate definitions\n - Tool: #codeql_lsp_completion \u2014 explore member predicates on types used in the query\n - Parameters: `file_path`, `line` (0-based), `character` (0-based), `workspace_uri` (pack root)\n - Run #codeql_pack_install first \u2014 LSP tools require resolved dependencies\n\n- [ ] **Step 6: Run tests** (if tests exist from Step 1)\n - Tool: #codeql_test_run\n - Parameters: `tests` = test directories\n - Gather: Pass/fail status, confirms query behavior\n\n### Phase 4: Create/Update Documentation\n\nBased on gathered context, create or update the documentation file.\n\n## Documentation Format\n\nThe documentation file (`QueryFileBaseName.md`) should follow this standardized format with these sections:\n\n### Section 1: Title and Description\n\n- H1 heading with the query name from @name metadata\n- One paragraph description from @description, expanded if needed\n\n### Section 2: Metadata Table\n\nA table with these rows:\n\n- ID: The @id value in backticks\n- Kind: The @kind value (problem, path-problem, etc.)\n- Severity: The @severity value\n- Precision: The @precision value\n- Tags: The @tags values\n\n### Section 3: Overview\n\nConcise explanation of what vulnerability/issue this query detects and why it matters. 2-4 sentences.\n\n### Section 4: Recommendation\n\nBrief guidance on how developers should fix issues flagged by this query. Include code patterns to use or avoid.\n\n### Section 5: Example\n\nTwo subsections:\n\n- **Vulnerable Code**: A code block showing a pattern that would be flagged by this query\n- **Fixed Code**: A code block showing the corrected version of the code\n\nUse the appropriate language identifier for the code blocks (e.g., `javascript`, `python`, `java`).\n\n### Section 6: References\n\nA list of links to:\n\n- Relevant CWE if security query\n- Relevant documentation or standards\n- CodeQL documentation for related concepts\n\n## Output Actions\n\nAfter generating documentation content:\n\n1. **For new documentation**: Create the file at `[QueryDirectory]/QueryFileBaseName.md`\n2. **For existing `.md` file**: Update the file with new content, preserving any custom sections\n3. **For existing `.qhelp` file**: Create new `.md` file (keeping `.qhelp` for backward compatibility)\n\n## Important Notes\n\n- **Be concise**: Documentation should be brief but complete. This is reference documentation, not tutorial content.\n- **Keep it current**: Documentation should reflect the current behavior of the query.\n- **Use examples from tests**: If unit tests exist, use those code patterns as examples.\n- **Standard format**: Always use the format above for consistency across all query documentation.\n- **Metadata accuracy**: Ensure documented metadata matches actual query metadata.\n- **For workshops**: Use `explain_codeql_query` prompt when creating workshop content that requires deeper explanations and visual diagrams.\n';
@@ -64265,6 +64391,9 @@ var document_codeql_query_prompt_default = '---\nagent: agent\n---\n\n# Document
64265
64391
  // src/prompts/explain-codeql-query.prompt.md
64266
64392
  var explain_codeql_query_prompt_default = '---\nagent: agent\n---\n\n# Explain a CodeQL Query (Workshop Learning Content)\n\nThis prompt guides you through gathering comprehensive context about a CodeQL query using MCP server tools, then generating detailed explanations suitable for CodeQL workshop learning content.\n\n## Purpose\n\nThe `explain_codeql_query` prompt is designed for creating **learning content** for CodeQL workshops and workshop improvements. It produces in-depth, educational explanations of how a query works, including visual diagrams.\n\nFor creating/updating **query documentation files** (`.md` or `.qhelp`), use the `document_codeql_query` prompt instead.\n\n## Required Inputs\n\n- **queryPath**: Path to the CodeQL query file (`.ql` or `.qlref`)\n- **language**: Target programming language (actions, cpp, csharp, go, java, javascript, python, ruby, swift)\n- **databasePath** (optional): Path to a real CodeQL database for profiling\n\n## Agent AI Instructions\n\n**Critical**: The evaluator logs and profiler outputs from CodeQL can be very large files. Use the MCP server tools to analyze them efficiently:\n\n- Use #profile_codeql_query_from_logs to extract pipeline timing, predicate evaluation order, tuple count progressions, RA operations, and dependencies from evaluator logs \u2014 this single tool provides all evaluator log analysis\n- Use #search_ql_code to find predicates, classes, or patterns across QL library files\n\n## Choosing a Database\n\nSeveral steps below require a CodeQL database. Determine which database to use:\n\n1. **User-provided `databasePath`** \u2014 use this if provided and valid (check with #codeql_resolve_database).\n2. **Test database** \u2014 if Step 1 finds tests, run them in Step 3 to create a `.testproj` database.\n3. **No database available** \u2014 skip Steps 4-6, and base the explanation on source code analysis only.\n\nStore the chosen database path as `$DB` for use in Steps 4-6.\n\n## Workflow Checklist\n\nYou MUST use the following MCP server tools in sequence to gather context before generating your explanation:\n\n### Phase 1: Query Discovery and Validation\n\n- [ ] **Step 1: Locate query files**\n - Tool: #find_codeql_query_files\n - Parameters: `queryPath` = provided query path\n - Gather: Query source file, test files, expected results, metadata location\n - Note: If tests exist, record the test directory path for later steps\n\n- [ ] **Step 2: Validate query structure**\n - Tool: #validate_codeql_query\n - Parameters: `query` = contents of the query file\n - Gather: Structural validation results, heuristic warnings/suggestions\n\n### Phase 2: Test Execution and Database Creation\n\n- [ ] **Step 3: Run existing tests** (if tests exist from Step 1)\n - Tool: #codeql_test_run\n - Parameters: `tests` = array of test directories from Step 1\n - Purpose: Ensures test database is created and current with test code\n - Gather: Test pass/fail status, test database path (`.testproj` directory)\n - **If no tests exist**: Skip this step. Use user-provided `databasePath` as `$DB`.\n\n### Phase 3: Code Structure Analysis (requires `$DB`)\n\nSkip this phase entirely if no database is available.\n\n- [ ] **Step 4: Generate PrintAST output**\n - Tool: #codeql_query_run\n - Parameters:\n - `queryName`: `"PrintAST"`\n - `queryLanguage`: provided language\n - `database`: `$DB`\n - `sourceFiles`: test source file names (or representative source files from the database)\n - `format`: `"graphtext"`\n - Gather: AST hierarchy showing code structure representation\n\n- [ ] **Step 5: Generate PrintCFG output** (for key functions)\n - Tool: #codeql_query_run\n - Parameters:\n - `queryName`: `"PrintCFG"`\n - `queryLanguage`: provided language\n - `database`: `$DB`\n - `sourceFunction`: key function name(s) from test code or query source\n - `format`: `"graphtext"`\n - Gather: Control flow graph showing execution paths\n\n### Phase 4: Query Profiling and Evaluation Order (requires `$DB`)\n\nSkip this phase entirely if no database is available.\n\n- [ ] **Step 6a: Run the query with evaluator logging**\n - Tool: #codeql_query_run (or #codeql_database_analyze)\n - Run the query against `$DB` with evaluator logging enabled\n - The tool returns the path to the evaluator log file (`.jsonl`)\n\n- [ ] **Step 6b: Profile from evaluator logs**\n - Tool: #profile_codeql_query_from_logs\n - Parameters:\n - `evaluatorLog`: path to the evaluator log file from Step 6a\n - Gather: Pipeline execution order, predicate timing data, tuple counts\n - **Critical**: This reveals the actual bottom-up evaluation order of predicates\n\n- [ ] **Step 7: Quick evaluate specific predicates** (as needed)\n - First, locate the predicate: Tool: #find_predicate_position with `file` and `name`\n - Then evaluate: Tool: #quick_evaluate with `file`, `db`, and `symbol`\n - Use when: You need more context on how a specific predicate or class behaves\n - Note: #find_class_position finds `class` definitions only, not `module` definitions\n - Note: #find_predicate_position returns 1-based positions; LSP tools use 0-based\n\n### Phase 5: Generate Explanation\n\nBased on all gathered context, generate your explanation with both **verbal** and **visual** components.\n\n## Key Aspects to Analyze in Profiler Output\n\nUnderstanding the query profiler output is critical for explaining how the query actually works. Look for:\n\n1. **Evaluation Order**: Which predicates are evaluated first (base predicates) vs last (dependent predicates)\n2. **Pipeline Timing**: Time taken for each pipeline stage - indicates complexity\n3. **Tuple Counts**: Number of results at each stage - shows data flow volume\n4. **RA Operations**: The relational algebra operations (SCAN, JOIN, AGGREGATE) reveal query execution strategy\n5. **Dependencies**: Which predicates depend on others (shown by evaluation order)\n\n## Output Format\n\n### Verbal Explanation Structure\n\nGenerate a single markdown document with these sections in order:\n\n1. **Query Overview** \u2014 2-3 sentence summary of what the query detects and why it matters.\n2. **Query Metadata** \u2014 Table with: Name, Description, Kind, ID, Tags, Precision, Severity (from `@` annotations).\n3. **What This Query Detects** \u2014 Security implications (CWE/OWASP if applicable), why the pattern is problematic, real-world attack scenarios.\n4. **How the Query Works** \u2014 Two subsections:\n - **Bottom-Up Evaluation Order**: Evaluation timeline table (Order, Predicate/Pipeline, Time ms, Tuples) derived from profiler data. Explain that CodeQL evaluates bottom-up.\n - **Key Components**: Imports, classes and characteristic predicates, helper predicates, data flow configuration (sources, sinks, sanitizers, additional flow steps), main query `from`/`where`/`select`.\n5. **Test Code Analysis** (if database was available) \u2014 AST structure insights from PrintAST, control flow insights from PrintCFG.\n6. **Example Patterns** \u2014 Positive test cases (should match) and negative test cases (should not match) with explanations.\n7. **Performance Characteristics** (if profiler data available) \u2014 Most expensive predicates, highest tuple counts, optimization opportunities.\n8. **Limitations and Edge Cases** \u2014 Patterns the query might miss, known false positive scenarios.\n\n### Visual Explanation: Mermaid Evaluation Diagram\n\nGenerate a `mermaid` `flowchart BU` (bottom-up) diagram showing the evaluation order derived from profiler data. Guidelines:\n\n- Use subgraphs to group predicates by evaluation phase (base, intermediate, flow analysis, final select)\n- Label nodes with actual predicate/class names from the query\n- Show dependency edges between predicates\n- Annotate expensive operations with timing (e.g., `[500ms]`)\n- Direction must be `BU` to reflect bottom-up evaluation\n\n## Important Notes\n\n- **Always use tools first**: Do not generate explanations based only on query source code. Use the MCP tools to gather actual runtime data.\n- **Use the profiler tool for evaluator logs**: Evaluator logs can be huge. Use #profile_codeql_query_from_logs which returns compact JSON with per-predicate metrics and a line-indexed detail file. Use `read_file` with the `detailLines` ranges from the response to access full RA operations and tuple progressions for any predicate \u2014 do not use CLI grep or read log files directly.\n- **Evaluation order matters**: CodeQL evaluates bottom-up, not top-down. The profiler output reveals the true execution order.\n- **Focus on learning**: This is for workshop content, so include educational context and explanations suitable for CodeQL learners.\n- **Visual diagrams**: Always include a mermaid diagram showing evaluation order.\n- **Reference documentation**: For actual QL evaluation semantics, see [Evaluation of QL programs](https://codeql.github.com/docs/ql-language-reference/evaluation-of-ql-programs/)\n';
64267
64393
 
64394
+ // src/prompts/find-overlapping-queries.prompt.md
64395
+ var find_overlapping_queries_prompt_default = '---\nagent: agent\n---\n\n# Find Overlapping Queries and Libraries\n\nUse the MCP server tools to discover existing `.ql` query files and `.qll` library\nfiles whose content may overlap with a new query design \u2014 **before** writing any new\ncode \u2014 so that reusable building blocks can be identified and incorporated rather than\nreimplemented from scratch.\n\n"Overlap" here includes:\n\n- A shared library (`.qll`) that already models a concept central to the new query\n (e.g. a class representing placement-new expressions, or a predicate identifying\n types with non-trivial destructors)\n- An existing query (`.ql`) whose logic intersects the new query\'s domain (e.g. an\n existing query that already detects misuse of placement-new, or already reasons\n about destructor triviality)\n- Utility predicates or classes in either file type that could be imported and reused\n directly, reducing the amount of new code needed\n\n## Use This Prompt When\n\n- Starting a new query and wanting to know what library support already exists for\n the concepts it must model\n- Unsure whether a query (or a close variant) already exists in the codebase\n- Looking for concrete QL code examples of how to model a particular language\n construct or pattern in the target language\n- Performing an audit of a query suite to identify potential consolidation\n opportunities\n\n## Prerequisites\n\n1. A clear description of the new query\'s **purpose and target constructs** (e.g.\n "detect placement-new calls on objects whose type has a non-trivial destructor")\n2. The **target language** (e.g. `cpp`, `java`, `python`)\n3. Optionally, the **pack root** \u2014 the directory containing `codeql-pack.yml` for the\n pack that will own the new query; this is used to locate project-specific libraries\n and existing queries in the same suite\n\n## Overview of the Approach\n\nThe core idea is to decompose the new query\'s description into a set of **key\nconcepts**, then search the available `.qll` library files and existing `.ql` query\nfiles for content that relates to those concepts. Finally, report which files contain\nrelevant material and highlight the specific classes, predicates, or modules that\ncould be reused.\n\n1. **Extract key concepts** from the query description\n2. **Resolve available library sources** for the target language and pack\n3. **Find candidate `.qll` files** \u2014 ranked by naming proximity to the key concepts\n4. **Enumerate symbols in candidate `.qll` files** to identify reusable definitions\n5. **Find candidate `.ql` query files** in the same pack and its dependencies\n6. **Inspect overlapping queries** to understand their scope and find reusable logic\n7. **Report findings** \u2014 which files and which specific definitions are most relevant\n\n## Step 1: Extract Key Concepts\n\nBefore touching any tools, decompose the query description into a set of\n**searchable key concepts**: concrete noun phrases (AST node types, predicates,\nlanguage-specific constructs) that are likely to appear in file names or class/\npredicate names.\n\nFor example, "placement-new calls on objects whose type has a non-trivial destructor"\ndecomposes into:\n\n- `PlacementNew` / `placement_new` / `NewExpr`\n- `NonTrivial` / `non_trivial` / `Trivial`\n- `Destructor` / `destructor` / `Dtor`\n\nRecord these key concept terms \u2014 they drive every subsequent search.\n\n## Step 2: Resolve Available Library Sources\n\nUse `codeql_resolve_library-path` to find every source root visible to the target\npack. If no pack root is known yet, use either a representative existing `.ql` file\nin the same language, or the language\'s default library root (typically\n`~/.codeql/packages`).\n\n```text\nTool: codeql_resolve_library-path\nParameters:\n query: /path/to/any-existing-query.ql # or use --additional-packs\n format: json\n```\n\nRead the returned list of source roots. For each root, list the directory tree to\nunderstand the overall structure before narrowing your search:\n\n```text\nTool: list_directory\nParameters:\n path: /returned/source/root\n```\n\nDo **not** preemptively discard any source root based on its name alone. The\nstructure of each root must be understood before filtering.\n\n## Step 3: Find Candidate `.qll` Files\n\nFor each source root, gather all `.qll` file paths:\n\n```text\nShell: find /source/root -name "*.qll" | sort\n```\n\nScan every path using the key concept terms from Step 1. A file is a **candidate**\nif its path or filename contains one or more of those terms, or if it lives in a\ndirectory whose name suggests domain relevance (e.g. `memory/`, `destructors/`,\n`initialization/`).\n\nPrioritize candidates as follows:\n\n- `.qll` files in the same directory as the planned new query \u2014 **highest priority**\n- `.qll` files elsewhere in the same pack \u2014 **very high priority**\n- `.qll` files in project-specific library packs \u2014 **high priority**\n- `.qll` files in downloaded direct dependencies \u2014 **standard priority**\n- `.qll` files in transitive dependencies \u2014 **lower priority**\n\nAim to identify the **top 5\u201310 most promising candidate `.qll` files** before\nproceeding. Breadth is important here: a small `.qll` file named `Destructor.qll`\nis more immediately useful than a 5000-line `Types.qll`, but both should be noted if\nrelevant.\n\n## Step 4: Enumerate Symbols in Candidate `.qll` Files\n\nFor each shortlisted candidate `.qll` file, retrieve its top-level definitions:\n\n```text\nTool: codeql_lsp_document_symbols\nParameters:\n file_path: /path/to/Candidate.qll\n names_only: true\n workspace_uri: /path/to/pack-root # plain directory containing codeql-pack.yml\n```\n\nNote: `workspace_uri` must be a **plain directory path**, not a `file://` URI. All\nline/character positions returned by LSP tools are **0-based**.\n\nScan the returned `symbols` array for classes, predicates, and modules whose names\ncontain or are closely related to the key concept terms. For any promising symbol,\nexpand its definition using `find_predicate_position` or `find_class_position` and\nthen `read_file` to inspect the actual implementation.\n\nNote: `find_predicate_position` and `find_class_position` use **1-based** line\nnumbers.\n\nRecord each relevant symbol as:\n\n```\nFile: /path/to/Candidate.qll\nSymbol: ClassName / predicateName\nRelevance: <which key concept it addresses>\nSummary: <one-sentence description of what it does>\n```\n\n## Step 5: Find Candidate Existing `.ql` Query Files\n\nExisting queries are an equally important source of reusable logic.\n\nFirst, list all `.ql` files in the target pack (and any closely related packs) using\nthe MCP tool `codeql_resolve_queries` or a recursive directory listing:\n\n```text\nTool: codeql_resolve_queries\nParameters:\n directory: /path/to/pack-root\n format: json\n```\n\nOr equivalently:\n\n```text\nShell: find /pack-root -name "*.ql" | sort\n```\n\nScan every file name using the key concept terms from Step 1. A query file is a\n**candidate** if:\n\n- Its file name contains one or more key concept terms, or\n- It lives in a subdirectory whose name suggests domain overlap, or\n- Its containing rule directory (e.g. `RULE-X-Y-Z/`) has a description that overlaps\n with the new query\'s domain (check `qlpack.yml` query metadata or directory names\n if available)\n\n## Step 6: Inspect Overlapping Query Files\n\nFor each candidate `.ql` file identified in Step 5:\n\n1. Read the file header (first 60 lines) to understand what the query detects:\n\n ```text\n Tool: read_file\n Parameters:\n file_path: /path/to/ExistingQuery.ql\n start_line: 1\n end_line: 60\n ```\n\n2. Use `codeql_lsp_document_symbols` to enumerate its own top-level definitions:\n\n ```text\n Tool: codeql_lsp_document_symbols\n Parameters:\n file_path: /path/to/ExistingQuery.ql\n names_only: true\n workspace_uri: /path/to/pack-root\n ```\n\n3. For any symbol whose name or kind maps to a key concept, retrieve its full\n definition using `find_predicate_position` / `find_class_position` and `read_file`\n to determine whether the logic could be reused by the new query.\n\n4. Note the import statements in the existing query. Any shared `.qll` imported\n there is a strong signal that the same import could benefit the new query.\n\nAim to identify **which specific lines or definitions** are most relevant \u2014 not just\nwhich file \u2014 so that the report gives actionable guidance.\n\n## Step 7: Report Findings\n\n### Relevant Library Definitions (`.qll` files)\n\nPresent a table of reusable definitions found in library files:\n\n| Symbol | File | Kind | Key Concept | Notes |\n| ---------------------- | ---------------------------------------------------------- | --------- | ------------ | ------------------------------------------------ |\n| `PlacementNewExpr` | `semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll:12` | class | PlacementNew | Models placement-new allocation sites |\n| `hasTrivialDestructor` | `semmle/code/cpp/Type.qll:340` | predicate | Destructor | Returns true if the type\'s destructor is trivial |\n\nFor each entry, state:\n\n- **How to import it**: the `import` statement needed to access the symbol\n- **How it maps**: which part of the new query could use this definition\n- **Limitation** (if any): cases where the existing definition does not fully cover\n the new query\'s needs\n\n### Overlapping Existing Queries (`.ql` files)\n\nPresent a table of existing queries whose logic intersects:\n\n| Query file | Rule | What it detects | Overlap area |\n| ---------------------------- | -------------------- | ---------------------------------------------- | ---------------------------------------- |\n| `RULE-7-5-3/PlacementNew.ql` | MISRA C++ Rule 7.5.3 | Placement-new calls without matching destroy \u2014 | Placement-new enumeration, type analysis |\n\nFor each overlapping query, state:\n\n- **Shared logic**: the specific class or predicate definitions that could be lifted\n into a shared `.qll` or imported directly\n- **Divergence**: how the existing query\'s intent differs from the new query\'s intent,\n so the developer understands what cannot be reused directly\n\n### Summary Recommendation\n\nEnd with a short paragraph (3\u20135 sentences) summarising:\n\n1. Which existing definitions provide the **strongest starting points** for the new\n query\n2. Whether a **shared `.qll`** should be created to house logic that would otherwise\n be duplicated\n3. Which aspects of the new query appear to have **no existing foundation** and will\n require original implementation\n\n## Worked Example\n\n> **Query description**: Detect placement-new calls in C++ involving object types\n> that have a non-trivial destructor, because the caller is responsible for manually\n> invoking the destructor and may forget to do so.\n>\n> **Language**: `cpp`\n>\n> **Pack root**: `/workspace/cpp/misra/src`\n\n**Key concepts extracted**: `PlacementNew`, `NewExpr`, `NonTrivial`, `Trivial`,\n`Destructor`, `Dtor`\n\n**Step 2** \u2014 resolve library paths for a representative query:\n\n```text\nTool: codeql_resolve_library-path\nParameters:\n query: /workspace/cpp/misra/src/rules/RULE-7-5-1/SomeQuery.ql\n```\n\nReturns roots such as:\n\n- `/workspace/cpp/common/src` (project library)\n- `/workspace/cpp/misra/src` (pack being worked on)\n- `~/.codeql/packages/codeql/cpp-all/1.4.0` (standard library)\n\n**Step 3** \u2014 scanning `~/.codeql/packages/codeql/cpp-all/1.4.0` for `*.qll`:\n\nCandidates matching key concepts:\n\n- `semmle/code/cpp/exprs/New.qll` \u2014 contains `NewExpr`, likely covers placement-new\n- `semmle/code/cpp/Type.qll` \u2014 may contain destructor triviality predicates\n- `semmle/code/cpp/Destructor.qll` (if it exists) \u2014 direct match on `Destructor`\n\n**Step 4** \u2014 `codeql_lsp_document_symbols` on `New.qll`:\n\n```json\n{ "name": "NewExpr", "kind": 5 }\n{ "name": "NewArrayExpr", "kind": 5 }\n{ "name": "PlacementNewExpr","kind": 5 } \u2190 highly relevant\n```\n\n`PlacementNewExpr` in `New.qll` exactly models placement-new allocations \u2014\nthis class should be imported and used directly in the new query rather than\nreimplementing it.\n\n**Step 5** \u2014 scanning `/workspace/cpp/misra/src` for `*.ql`:\n\nCandidates matching key concepts:\n\n- `rules/RULE-12-2-1/DestructorMustBeCalledExplicitly.ql` \u2014 destructor relevance\n- `rules/RULE-6-2-2/PlacementNewLifetime.ql` \u2014 placement-new relevance\n\n**Step 6** \u2014 reading `PlacementNewLifetime.ql` header:\n\nThe file imports `semmle.code.cpp.exprs.New` and defines a local predicate\n`placementNewTarget()` that wraps `PlacementNewExpr.getAllocatedType()`.\nThis predicate and the surrounding type-resolution logic can serve as a template.\n\n# Conclusion\n\nDo **not** write or modify any code during this analysis.\n\nAs you work through this task, ask yourself:\n\n- Have I changed any code, even though that was not my task, or am I about to?\n Stop, do not change any code!\n- Did I extract enough key concepts to drive a thorough file-name search?\n- Did I inspect both library `.qll` files **and** existing `.ql` query files?\n- Did I identify specific symbols (not just files) that are relevant?\n- Did I report the import path needed to access each reusable symbol?\n- Did I summarise which parts of the new query still require original implementation?\n- Did I use the suggested tools to their fullest extent before concluding?\n- Did I report any difficulties encountered while resolving library paths or reading\n files?\n';
64396
+
64268
64397
  // src/prompts/ql-lsp-iterative-development.prompt.md
64269
64398
  var ql_lsp_iterative_development_prompt_default = '---\nagent: agent\n---\n\n# Iterative CodeQL Development with LSP Tools\n\nUse the MCP server tools from this prompt to iteratively develop and refine CodeQL queries using the LSP-powered tools.\nThese "iterative" tools work entirely through file paths and numeric positions.\nEvery operation is expressible as a tool call with explicit `file_path`, `line`, and `character` parameters.\nThus, this prompt can be used in any environment where the query files are on disk, and it does not require any special editor integration.\n\n## Use This Prompt When\n\n- Exploring unfamiliar CodeQL libraries to discover available classes and predicates\n- Incrementally building a query clause-by-clause with real-time feedback\n- Navigating from a type usage to its definition to understand its API\n- Finding all usages of a predicate to learn patterns from existing queries\n- Validating query fragments before assembling a complete query\n- Debugging individual predicates by evaluating them in isolation against a database\n\n## Prerequisites\n\n1. A CodeQL pack with `codeql-pack.yml` on disk\n2. Dependencies installed via #codeql_pack_install (pointing at the pack directory)\n3. Query files saved to disk (LSP tools operate on files, not inline strings)\n\n## Key Concept: Positions Are File Path + Line + Character\n\nAll LSP tools identify locations using three values:\n\n- `file_path`: absolute path to a `.ql` or `.qll` file\n- `line`: **0-based** line number (line 1 in the file = `line: 0`)\n- `character`: **0-based** column offset within that line\n\nThe `workspace_uri` parameter must point to the **pack root directory** (the folder\ncontaining `codeql-pack.yml`) for import resolution to work. Without it, completions\nand definitions for imported libraries will be empty.\n\n> **Critical**: LSP line/character positions are 0-based, but `read_file`,\n> #find_predicate_position, and #find_class_position return 1-based positions.\n> Always subtract 1 when passing their output to LSP tools.\n\n## Step 1: Discover Available Types with Completions\n\nUse #codeql_lsp_completion to explore what types and predicates are available at any\nposition in a query file. This replaces manual documentation browsing.\n\n**Example**: To see what classes are available in a `from` clause after `import javascript`:\n\n```text\nTool: codeql_lsp_completion\nParameters:\n file_path: /path/to/your/query.ql\n line: 9 # 0-based line of the `from` clause\n character: 5 # position after `from ` where you want completions\n workspace_uri: /path/to/pack-root # directory containing codeql-pack.yml\n```\n\nCompletions include class names with full documentation. For example, requesting\ncompletions in a JavaScript query\'s `from` clause returns 150+ types like\n`CallNode`, `PropWrite`, `RemoteFlowSource`, etc., each with docstrings.\n\n**Exploring member predicates**: To see what methods a variable offers, request\ncompletions after the dot. For example, if `pw` is typed as `DataFlow::PropWrite`,\nrequesting completions at the position after `pw.` returns all member predicates\nlike `getPropertyName()`, `getRhs()`, `getBase()`, `writes(base, prop, rhs)`,\neach with full signature and documentation.\n\n## Step 2: Navigate to Definitions\n\nUse #codeql_lsp_definition to find where a class, predicate, or module is defined.\nThis returns the file URI and line range of the definition \u2014 even into library pack\nfiles you haven\'t opened.\n\n```text\nTool: codeql_lsp_definition\nParameters:\n file_path: /path/to/your/query.ql\n line: 11 # 0-based line containing the symbol\n character: 30 # 0-based column within the symbol name\n workspace_uri: /path/to/pack-root\n```\n\n**Example**: Navigating to `RemoteFlowSource` at line 12, character 30 returns:\n\n```text\nuri: file:///.../.codeql/packages/codeql/javascript-all/2.6.19/\n semmle/javascript/security/dataflow/RemoteFlowSources.qll\nstartLine: 14, startCharacter: 17\n```\n\nYou can then read that file to understand the class\'s API. This is how you discover\nwhat predicates a type offers without documentation \u2014 go to the definition and read\nthe source.\n\n## Step 3: Find All References\n\nUse #codeql_lsp_references to find how a symbol is used across the workspace.\n\n```text\nTool: codeql_lsp_references\nParameters:\n file_path: /path/to/your/query.ql\n line: 11 # 0-based line\n character: 30 # 0-based column within the symbol\n workspace_uri: /path/to/pack-root\n```\n\n> **Scope note**: References are scoped to the pack identified by `workspace_uri`.\n> To find usages in library code, point `workspace_uri` to the library pack root.\n> For usages within your own pack only, point it to your pack root.\n\nThis is invaluable for learning how experienced query authors use a predicate \u2014\nfind real usage examples instead of guessing from documentation.\n\n## Step 4: Locate Symbols with Position Finders\n\nUse #find_predicate_position and #find_class_position to locate where a specific\nsymbol is defined in a file. These return **1-based** line/column positions.\n\n```text\nTool: find_predicate_position\nParameters:\n file: /path/to/your/query.ql\n name: isSource\nReturns: { start_line: 12, start_col: 13, end_line: 12, end_col: 20 }\n```\n\n> **Note**: #find_class_position finds `class` definitions only \u2014 it does not find\n> `module` definitions. Use #find_predicate_position for predicates inside modules,\n> or use #search_ql_code to search across QL files by text or regex pattern.\n\n**Combining with LSP tools**: To navigate to a predicate\'s definition in library code:\n\n1. Use #find_predicate_position to get its 1-based position\n2. Subtract 1 from line/col to convert to 0-based\n3. Pass to #codeql_lsp_definition to jump to the underlying type\n\n## Step 5: Quick-Evaluate Individual Predicates\n\nUse #quick_evaluate to evaluate a single predicate or class against a database\nwithout running the full query. This is the fastest way to debug whether a predicate\nmatches what you expect.\n\n```text\nTool: quick_evaluate\nParameters:\n file: /path/to/your/query.ql\n db: /path/to/test-database.testproj\n symbol: isSink\n output_path: /tmp/quickeval-results # optional, for inspecting bqrs output\n```\n\nThe tool evaluates just that symbol (predicate or class) and returns the result path.\nUse #codeql_bqrs_decode on the output to inspect results in CSV or JSON format.\n\n## Step 6: Validate at Multiple Levels\n\nUse the right validation tool for each situation:\n\n| Tool | Use When | Input | Resolves Imports? |\n| ----------------------- | --------------------------------------- | ------------------ | ------------------- |\n| #validate_codeql_query | Quick structural check | Inline QL string | No (heuristic only) |\n| #codeql_lsp_diagnostics | Syntax/semantic validation of fragments | Inline QL string | No |\n| #codeql_query_compile | Full compilation check | On-disk `.ql` file | Yes |\n| #codeql_test_run | End-to-end result validation | Test directory | Yes |\n\n**#codeql_lsp_diagnostics** validates QL syntax and semantics for inline code snippets,\nbut **cannot resolve `import` statements** (like `import javascript`). Use it for:\n\n- Checking predicate signatures and QL syntax\n- Verifying `from`/`where`/`select` clause structure\n- Catching type errors in import-free QL fragments\n\nFor queries with imports, always use #codeql_query_compile on the saved file.\n\n## Iterative Development Loop\n\n```text\n1. Write/modify a clause in the query file (save to disk)\n \u2193\n2. codeql_lsp_completion \u2192 verify context is valid (non-empty = good)\n \u2193\n3. codeql_query_compile \u2192 check for compilation errors\n \u2193\n4. codeql_test_run \u2192 validate against expected results\n \u2193\n5. If unexpected results: quick_evaluate on individual predicates\n \u2193\n6. If predicate is wrong: codeql_lsp_completion to explore the API\n \u2193\n7. If types are unclear: codeql_lsp_definition to read the source\n \u2193\n8. If stuck: codeql_lsp_references to find usage examples\n \u2193\n9. Repeat from step 1\n```\n\n## Worked Example: Building a Taint-Tracking Query\n\nThis example shows the tools in action for building a JavaScript XSS query.\n\n### 1. Create the query file and install dependencies\n\nWrite a `.ql` file with `import javascript` and a skeleton `from`/`where`/`select`.\nRun #codeql_pack_install on the pack directory.\n\n### 2. Explore sink types\n\nRequest completions in the `from` clause to discover `DataFlow::PropWrite`:\n\n```text\ncodeql_lsp_completion(file_path=..., line=9, character=5, workspace_uri=pack_root)\n\u2192 155 completions including PropWrite, CallNode, MethodCallNode, ...\n```\n\n### 3. Explore `PropWrite` member predicates\n\nAfter typing `pw.` in the `where` clause, request completions:\n\n```text\ncodeql_lsp_completion(file_path=..., line=12, character=9, workspace_uri=pack_root)\n\u2192 43 predicates: getPropertyName(), getRhs(), getBase(), writes(), ...\n```\n\n### 4. Navigate to `RemoteFlowSource` definition\n\n```text\ncodeql_lsp_definition(file_path=..., line=11, character=30, workspace_uri=pack_root)\n\u2192 RemoteFlowSources.qll line 14 in codeql/javascript-all\n```\n\n### 5. Compile and test incrementally\n\n```text\ncodeql_query_compile(query=file_path) \u2192 check for errors\ncodeql_test_run(tests=[test_dir], learn=true) \u2192 populate .expected files\n```\n\n### 6. Debug a predicate in isolation\n\n```text\nfind_predicate_position(file=..., name="isSink") \u2192 line 16, col 13\nquick_evaluate(file=..., db=test.testproj, symbol="isSink") \u2192 inspect results\n```\n\n## Important Notes\n\n- **All LSP tools use 0-based positions**. #find_class_position and\n #find_predicate_position return 1-based positions. Convert before combining.\n- **`workspace_uri` must be the pack root** (the directory containing\n `codeql-pack.yml`). Without it, completions and definitions will be empty.\n- **Run #codeql_pack_install first**. LSP tools require resolved dependencies.\n- **#codeql_lsp_diagnostics cannot resolve imports**. For `import javascript`\n and similar, use #codeql_query_compile on the on-disk file instead.\n- **#find_class_position finds `class` only**, not `module` definitions.\n Use #search_ql_code or #find_predicate_position for predicates inside modules.\n- **#codeql_lsp_references scope** depends on `workspace_uri`. Point it at\n a library pack root to find usages across library code.\n';
64270
64399
 
@@ -64291,8 +64420,10 @@ var workshop_creation_workflow_prompt_default = '---\nagent: agent\n---\n\n# Cre
64291
64420
 
64292
64421
  // src/prompts/prompt-loader.ts
64293
64422
  var PROMPT_TEMPLATES = {
64423
+ "check-for-duplicated-code.prompt.md": check_for_duplicated_code_prompt_default,
64294
64424
  "document-codeql-query.prompt.md": document_codeql_query_prompt_default,
64295
64425
  "explain-codeql-query.prompt.md": explain_codeql_query_prompt_default,
64426
+ "find-overlapping-queries.prompt.md": find_overlapping_queries_prompt_default,
64296
64427
  "ql-lsp-iterative-development.prompt.md": ql_lsp_iterative_development_prompt_default,
64297
64428
  "ql-tdd-advanced.prompt.md": ql_tdd_advanced_prompt_default,
64298
64429
  "ql-tdd-basic.prompt.md": ql_tdd_basic_prompt_default,
@@ -64324,6 +64455,7 @@ function processPromptTemplate(template, variables) {
64324
64455
  }
64325
64456
 
64326
64457
  // src/prompts/workflow-prompts.ts
64458
+ init_package_paths();
64327
64459
  init_logger();
64328
64460
  var SUPPORTED_LANGUAGES = [
64329
64461
  "actions",
@@ -64336,6 +64468,82 @@ var SUPPORTED_LANGUAGES = [
64336
64468
  "ruby",
64337
64469
  "swift"
64338
64470
  ];
64471
+ function markdownInlineCode(value) {
64472
+ const normalized = value.replace(/\r\n|\r|\n/g, " ");
64473
+ let maxRun = 0;
64474
+ let currentRun = 0;
64475
+ for (const ch of normalized) {
64476
+ if (ch === "`") {
64477
+ currentRun += 1;
64478
+ if (currentRun > maxRun) {
64479
+ maxRun = currentRun;
64480
+ }
64481
+ } else {
64482
+ currentRun = 0;
64483
+ }
64484
+ }
64485
+ const fence = "`".repeat(maxRun + 1);
64486
+ return `${fence}${normalized}${fence}`;
64487
+ }
64488
+ function blockedPathError(result, paramName) {
64489
+ const message = result.warning ?? `The provided ${paramName} could not be resolved safely and cannot be used.`;
64490
+ return {
64491
+ messages: [
64492
+ {
64493
+ role: "user",
64494
+ content: {
64495
+ type: "text",
64496
+ text: `${message}
64497
+
64498
+ The workflow cannot proceed because the ${paramName} is not allowed.`
64499
+ }
64500
+ }
64501
+ ]
64502
+ };
64503
+ }
64504
+ async function resolvePromptFilePath(filePath, workspaceRoot) {
64505
+ if (!filePath || filePath.trim() === "") {
64506
+ return {
64507
+ resolvedPath: filePath ?? "",
64508
+ warning: "\u26A0 **File path is empty.** Please provide a valid file path."
64509
+ };
64510
+ }
64511
+ let effectivePath = filePath;
64512
+ if (/^file:\/\//i.test(filePath.trim())) {
64513
+ try {
64514
+ effectivePath = fileURLToPath3(filePath.trim());
64515
+ } catch {
64516
+ return {
64517
+ resolvedPath: "",
64518
+ blocked: true,
64519
+ warning: `\u26A0 **File path** \`${filePath}\` **is not a valid file URI.**`
64520
+ };
64521
+ }
64522
+ }
64523
+ const effectiveRoot = workspaceRoot ?? getUserWorkspaceDir();
64524
+ const normalizedPath = normalize(effectivePath);
64525
+ const inputWasAbsolute = isAbsolute7(normalizedPath);
64526
+ const absolutePath = inputWasAbsolute ? normalizedPath : resolve13(effectiveRoot, normalizedPath);
64527
+ if (!inputWasAbsolute) {
64528
+ const rel = relative(effectiveRoot, absolutePath);
64529
+ if (rel === ".." || rel.startsWith(`..${sep2}`) || isAbsolute7(rel)) {
64530
+ return {
64531
+ blocked: true,
64532
+ resolvedPath: "",
64533
+ warning: "\u26A0 **File path resolves outside the workspace root.** The path has been blocked for security."
64534
+ };
64535
+ }
64536
+ }
64537
+ try {
64538
+ await access2(absolutePath);
64539
+ } catch {
64540
+ return {
64541
+ resolvedPath: absolutePath,
64542
+ warning: `\u26A0 **File path** ${markdownInlineCode(filePath)} **does not exist.**`
64543
+ };
64544
+ }
64545
+ return { resolvedPath: absolutePath };
64546
+ }
64339
64547
  var testDrivenDevelopmentSchema = external_exports.object({
64340
64548
  language: external_exports.enum(SUPPORTED_LANGUAGES).describe("Programming language for the query"),
64341
64549
  queryName: external_exports.string().optional().describe("Name of the query to develop")
@@ -64354,23 +64562,23 @@ var workshopCreationWorkflowSchema = external_exports.object({
64354
64562
  numStages: external_exports.coerce.number().optional().describe("Number of incremental stages (default: 4-8)")
64355
64563
  });
64356
64564
  var qlTddBasicSchema = external_exports.object({
64357
- language: external_exports.enum(SUPPORTED_LANGUAGES).optional().describe("Programming language for the query (optional)"),
64565
+ language: external_exports.enum(SUPPORTED_LANGUAGES).describe("Programming language for the query"),
64358
64566
  queryName: external_exports.string().optional().describe("Name of the query to develop")
64359
64567
  });
64360
64568
  var qlTddAdvancedSchema = external_exports.object({
64361
64569
  database: external_exports.string().optional().describe("Path to the CodeQL database for analysis"),
64362
- language: external_exports.enum(SUPPORTED_LANGUAGES).optional().describe("Programming language for the query (optional)"),
64570
+ language: external_exports.enum(SUPPORTED_LANGUAGES).describe("Programming language for the query"),
64363
64571
  queryName: external_exports.string().optional().describe("Name of the query to develop")
64364
64572
  });
64365
64573
  var sarifRankSchema = external_exports.object({
64366
64574
  queryId: external_exports.string().optional().describe("CodeQL query/rule identifier"),
64367
- sarifPath: external_exports.string().optional().describe("Path to the SARIF file to analyze")
64575
+ sarifPath: external_exports.string().describe("Path to the SARIF file to analyze")
64368
64576
  });
64369
64577
  var describeFalsePositivesSchema = external_exports.object({
64370
- queryPath: external_exports.string().optional().describe("Path to the CodeQL query file")
64578
+ queryPath: external_exports.string().describe("Path to the CodeQL query file")
64371
64579
  });
64372
64580
  var explainCodeqlQuerySchema = external_exports.object({
64373
- databasePath: external_exports.string().optional().describe("Optional path to a real CodeQL database for profiling"),
64581
+ databasePath: external_exports.string().optional().describe("Path to a CodeQL database for profiling"),
64374
64582
  language: external_exports.enum(SUPPORTED_LANGUAGES).describe("Programming language of the query"),
64375
64583
  queryPath: external_exports.string().describe("Path to the CodeQL query file (.ql or .qlref)")
64376
64584
  });
@@ -64378,14 +64586,108 @@ var documentCodeqlQuerySchema = external_exports.object({
64378
64586
  language: external_exports.enum(SUPPORTED_LANGUAGES).describe("Programming language of the query"),
64379
64587
  queryPath: external_exports.string().describe("Path to the CodeQL query file (.ql or .qlref)")
64380
64588
  });
64589
+ var checkForDuplicatedCodeSchema = external_exports.object({
64590
+ queryPath: external_exports.string().describe("Path to the .ql or .qll file to audit for duplicated definitions"),
64591
+ workspaceUri: external_exports.string().optional().describe("Pack root directory containing codeql-pack.yml (for LSP resolution)")
64592
+ });
64593
+ var findOverlappingQueriesSchema = external_exports.object({
64594
+ queryDescription: external_exports.string().describe(
64595
+ `Description of the new query's purpose and target constructs (e.g. "detect placement-new on types with non-trivial destructors")`
64596
+ ),
64597
+ language: external_exports.enum(SUPPORTED_LANGUAGES).describe("Target language for the new query (e.g. cpp, java, python)"),
64598
+ packRoot: external_exports.string().optional().describe("Directory containing codeql-pack.yml for the pack that will own the new query")
64599
+ });
64381
64600
  var qlLspIterativeDevelopmentSchema = external_exports.object({
64382
- language: external_exports.enum(SUPPORTED_LANGUAGES).optional().describe("Programming language for the query"),
64383
- queryPath: external_exports.string().optional().describe("Path to the query file being developed"),
64601
+ language: external_exports.enum(SUPPORTED_LANGUAGES).describe("Programming language for the query"),
64602
+ queryPath: external_exports.string().describe("Path to the query file being developed"),
64384
64603
  workspaceUri: external_exports.string().optional().describe("Workspace URI for LSP dependency resolution")
64385
64604
  });
64605
+ function toPermissiveShape(shape) {
64606
+ const permissive = {};
64607
+ for (const [key, zodType] of Object.entries(shape)) {
64608
+ permissive[key] = widenZodType(zodType);
64609
+ }
64610
+ return permissive;
64611
+ }
64612
+ function widenZodType(zodType) {
64613
+ if (zodType instanceof external_exports.ZodOptional) {
64614
+ const inner = zodType.unwrap();
64615
+ const widenedInner = widenZodType(inner);
64616
+ if (widenedInner === inner) return zodType;
64617
+ const result = widenedInner.optional();
64618
+ const desc = zodType.description;
64619
+ return desc ? result.describe(desc) : result;
64620
+ }
64621
+ if (zodType instanceof external_exports.ZodEnum) {
64622
+ const desc = zodType.description;
64623
+ const replacement = external_exports.string();
64624
+ return desc ? replacement.describe(desc) : replacement;
64625
+ }
64626
+ return zodType;
64627
+ }
64628
+ function formatValidationError(promptName, error2) {
64629
+ const lines = [
64630
+ `\u26A0 **Invalid input for \`${promptName}\`**`,
64631
+ ""
64632
+ ];
64633
+ for (const issue2 of error2.issues) {
64634
+ const field = issue2.path.length > 0 ? issue2.path.join(".") : "input";
64635
+ if (issue2.code === "invalid_enum_value" && "options" in issue2) {
64636
+ const opts = issue2.options.join(", ");
64637
+ lines.push(
64638
+ `- **\`${field}\`**: received ${markdownInlineCode(String(issue2.received))} \u2014 must be one of: ${opts}`
64639
+ );
64640
+ } else if (issue2.code === "invalid_type") {
64641
+ lines.push(
64642
+ `- **\`${field}\`**: expected ${issue2.expected}, received ${issue2.received}`
64643
+ );
64644
+ } else {
64645
+ lines.push(`- **\`${field}\`**: ${issue2.message}`);
64646
+ }
64647
+ }
64648
+ lines.push(
64649
+ "",
64650
+ "Please correct the input and try again."
64651
+ );
64652
+ return lines.join("\n");
64653
+ }
64654
+ function createSafePromptHandler(promptName, strictSchema, handler) {
64655
+ return async (rawArgs) => {
64656
+ const parseResult = strictSchema.safeParse(rawArgs);
64657
+ if (!parseResult.success) {
64658
+ const errorText = formatValidationError(promptName, parseResult.error);
64659
+ logger.warn(`Prompt ${promptName} validation failed: ${parseResult.error.message}`);
64660
+ return {
64661
+ messages: [{
64662
+ role: "user",
64663
+ content: { type: "text", text: errorText }
64664
+ }]
64665
+ };
64666
+ }
64667
+ try {
64668
+ return await handler(parseResult.data);
64669
+ } catch (err) {
64670
+ const msg = err instanceof Error ? err.message : String(err);
64671
+ logger.error(`Prompt ${promptName} handler error: ${msg}`);
64672
+ return {
64673
+ messages: [{
64674
+ role: "user",
64675
+ content: {
64676
+ type: "text",
64677
+ text: `\u26A0 **Error in \`${promptName}\`**: ${msg}
64678
+
64679
+ Please check your inputs and try again.`
64680
+ }
64681
+ }]
64682
+ };
64683
+ }
64684
+ };
64685
+ }
64386
64686
  var WORKFLOW_PROMPT_NAMES = [
64687
+ "check_for_duplicated_code",
64387
64688
  "document_codeql_query",
64388
64689
  "explain_codeql_query",
64690
+ "find_overlapping_queries",
64389
64691
  "ql_lsp_iterative_development",
64390
64692
  "ql_tdd_advanced",
64391
64693
  "ql_tdd_basic",
@@ -64400,262 +64702,387 @@ function registerWorkflowPrompts(server) {
64400
64702
  server.prompt(
64401
64703
  "test_driven_development",
64402
64704
  "Test-driven development workflow for CodeQL queries using MCP tools",
64403
- testDrivenDevelopmentSchema.shape,
64404
- async ({ language, queryName }) => {
64405
- const template = loadPromptTemplate("ql-tdd-basic.prompt.md");
64406
- const content = processPromptTemplate(template, {
64407
- language,
64408
- queryName: queryName || "[QueryName]"
64409
- });
64410
- return {
64411
- messages: [
64412
- {
64413
- role: "user",
64414
- content: {
64415
- type: "text",
64416
- text: `## Context
64705
+ toPermissiveShape(testDrivenDevelopmentSchema.shape),
64706
+ createSafePromptHandler(
64707
+ "test_driven_development",
64708
+ testDrivenDevelopmentSchema,
64709
+ async ({ language, queryName }) => {
64710
+ const template = loadPromptTemplate("ql-tdd-basic.prompt.md");
64711
+ const content = processPromptTemplate(template, {
64712
+ language,
64713
+ queryName: queryName || "[QueryName]"
64714
+ });
64715
+ return {
64716
+ messages: [
64717
+ {
64718
+ role: "user",
64719
+ content: {
64720
+ type: "text",
64721
+ text: `## Context
64417
64722
 
64418
64723
  - **Language**: ${language}
64419
64724
  ${queryName ? `- **Query Name**: ${queryName}
64420
64725
  ` : ""}
64421
64726
  ${content}`
64727
+ }
64422
64728
  }
64423
- }
64424
- ]
64425
- };
64426
- }
64729
+ ]
64730
+ };
64731
+ }
64732
+ )
64427
64733
  );
64428
64734
  server.prompt(
64429
64735
  "tools_query_workflow",
64430
64736
  "Guide for using built-in tools queries (PrintAST, PrintCFG, CallGraphFrom, CallGraphTo) to understand code structure",
64431
- toolsQueryWorkflowSchema.shape,
64432
- async ({
64433
- language,
64434
- database,
64435
- sourceFiles,
64436
- sourceFunction,
64437
- targetFunction
64438
- }) => {
64439
- const template = loadPromptTemplate("tools-query-workflow.prompt.md");
64440
- const content = processPromptTemplate(template, {
64441
- language,
64442
- database
64443
- });
64444
- const contextSection = buildToolsQueryContext(
64445
- language,
64446
- database,
64447
- sourceFiles,
64448
- sourceFunction,
64449
- targetFunction
64450
- );
64451
- return {
64452
- messages: [
64453
- {
64454
- role: "user",
64455
- content: {
64456
- type: "text",
64457
- text: contextSection + content
64737
+ toPermissiveShape(toolsQueryWorkflowSchema.shape),
64738
+ createSafePromptHandler(
64739
+ "tools_query_workflow",
64740
+ toolsQueryWorkflowSchema,
64741
+ async ({ language, database, sourceFiles, sourceFunction, targetFunction }) => {
64742
+ const template = loadPromptTemplate("tools-query-workflow.prompt.md");
64743
+ const warnings = [];
64744
+ const dbResult = await resolvePromptFilePath(database);
64745
+ if (dbResult.blocked) return blockedPathError(dbResult, "database path");
64746
+ const resolvedDatabase = dbResult.resolvedPath;
64747
+ if (dbResult.warning) warnings.push(dbResult.warning);
64748
+ const content = processPromptTemplate(template, {
64749
+ language,
64750
+ database: resolvedDatabase
64751
+ });
64752
+ const contextSection = buildToolsQueryContext(
64753
+ language,
64754
+ resolvedDatabase,
64755
+ sourceFiles,
64756
+ sourceFunction,
64757
+ targetFunction
64758
+ );
64759
+ const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
64760
+ return {
64761
+ messages: [
64762
+ {
64763
+ role: "user",
64764
+ content: {
64765
+ type: "text",
64766
+ text: warningSection + contextSection + content
64767
+ }
64458
64768
  }
64459
- }
64460
- ]
64461
- };
64462
- }
64769
+ ]
64770
+ };
64771
+ }
64772
+ )
64463
64773
  );
64464
64774
  server.prompt(
64465
64775
  "workshop_creation_workflow",
64466
64776
  "Guide for creating CodeQL query development workshops from production-grade queries",
64467
- workshopCreationWorkflowSchema.shape,
64468
- async ({ queryPath, language, workshopName, numStages }) => {
64469
- const template = loadPromptTemplate("workshop-creation-workflow.prompt.md");
64470
- const derivedName = workshopName || basename7(queryPath).replace(/\.(ql|qlref)$/, "").toLowerCase().replace(/[^a-z0-9]+/g, "-") || "codeql-workshop";
64471
- const contextSection = buildWorkshopContext(
64472
- queryPath,
64473
- language,
64474
- derivedName,
64475
- numStages
64476
- );
64477
- return {
64478
- messages: [
64479
- {
64480
- role: "user",
64481
- content: {
64482
- type: "text",
64483
- text: contextSection + template
64777
+ toPermissiveShape(workshopCreationWorkflowSchema.shape),
64778
+ createSafePromptHandler(
64779
+ "workshop_creation_workflow",
64780
+ workshopCreationWorkflowSchema,
64781
+ async ({ queryPath, language, workshopName, numStages }) => {
64782
+ const template = loadPromptTemplate("workshop-creation-workflow.prompt.md");
64783
+ const warnings = [];
64784
+ const qpResult = await resolvePromptFilePath(queryPath);
64785
+ if (qpResult.blocked) return blockedPathError(qpResult, "query path");
64786
+ const resolvedQueryPath = qpResult.resolvedPath;
64787
+ if (qpResult.warning) warnings.push(qpResult.warning);
64788
+ const derivedName = workshopName || basename7(resolvedQueryPath).replace(/\.(ql|qlref)$/, "").toLowerCase().replace(/[^a-z0-9]+/g, "-") || "codeql-workshop";
64789
+ const contextSection = buildWorkshopContext(
64790
+ resolvedQueryPath,
64791
+ language,
64792
+ derivedName,
64793
+ numStages
64794
+ );
64795
+ const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
64796
+ return {
64797
+ messages: [
64798
+ {
64799
+ role: "user",
64800
+ content: {
64801
+ type: "text",
64802
+ text: warningSection + contextSection + template
64803
+ }
64484
64804
  }
64485
- }
64486
- ]
64487
- };
64488
- }
64805
+ ]
64806
+ };
64807
+ }
64808
+ )
64489
64809
  );
64490
64810
  server.prompt(
64491
64811
  "ql_tdd_basic",
64492
64812
  "Test-driven CodeQL query development checklist - write tests first, implement query, iterate until tests pass",
64493
- qlTddBasicSchema.shape,
64494
- async ({ language, queryName }) => {
64495
- const template = loadPromptTemplate("ql-tdd-basic.prompt.md");
64496
- let contextSection = "## Your Development Context\n\n";
64497
- if (language) {
64813
+ toPermissiveShape(qlTddBasicSchema.shape),
64814
+ createSafePromptHandler(
64815
+ "ql_tdd_basic",
64816
+ qlTddBasicSchema,
64817
+ async ({ language, queryName }) => {
64818
+ const template = loadPromptTemplate("ql-tdd-basic.prompt.md");
64819
+ let contextSection = "## Your Development Context\n\n";
64498
64820
  contextSection += `- **Language**: ${language}
64499
64821
  `;
64500
- }
64501
- if (queryName) {
64502
- contextSection += `- **Query Name**: ${queryName}
64822
+ if (queryName) {
64823
+ contextSection += `- **Query Name**: ${queryName}
64503
64824
  `;
64504
- }
64505
- if (language || queryName) {
64825
+ }
64506
64826
  contextSection += "\n";
64507
- }
64508
- return {
64509
- messages: [
64510
- {
64511
- role: "user",
64512
- content: {
64513
- type: "text",
64514
- text: contextSection + template
64827
+ return {
64828
+ messages: [
64829
+ {
64830
+ role: "user",
64831
+ content: {
64832
+ type: "text",
64833
+ text: contextSection + template
64834
+ }
64515
64835
  }
64516
- }
64517
- ]
64518
- };
64519
- }
64836
+ ]
64837
+ };
64838
+ }
64839
+ )
64520
64840
  );
64521
64841
  server.prompt(
64522
64842
  "ql_tdd_advanced",
64523
64843
  "Advanced test-driven CodeQL development with AST visualization, control flow, and call graph analysis",
64524
- qlTddAdvancedSchema.shape,
64525
- async ({ language, queryName, database }) => {
64526
- const template = loadPromptTemplate("ql-tdd-advanced.prompt.md");
64527
- let contextSection = "## Your Development Context\n\n";
64528
- if (language) {
64844
+ toPermissiveShape(qlTddAdvancedSchema.shape),
64845
+ createSafePromptHandler(
64846
+ "ql_tdd_advanced",
64847
+ qlTddAdvancedSchema,
64848
+ async ({ language, queryName, database }) => {
64849
+ const template = loadPromptTemplate("ql-tdd-advanced.prompt.md");
64850
+ const warnings = [];
64851
+ let resolvedDatabase = database;
64852
+ if (database) {
64853
+ const dbResult = await resolvePromptFilePath(database);
64854
+ if (dbResult.blocked) return blockedPathError(dbResult, "database path");
64855
+ resolvedDatabase = dbResult.resolvedPath;
64856
+ if (dbResult.warning) warnings.push(dbResult.warning);
64857
+ }
64858
+ let contextSection = "## Your Development Context\n\n";
64529
64859
  contextSection += `- **Language**: ${language}
64530
64860
  `;
64531
- }
64532
- if (queryName) {
64533
- contextSection += `- **Query Name**: ${queryName}
64861
+ if (queryName) {
64862
+ contextSection += `- **Query Name**: ${queryName}
64534
64863
  `;
64535
- }
64536
- if (database) {
64537
- contextSection += `- **Database**: ${database}
64864
+ }
64865
+ if (resolvedDatabase) {
64866
+ contextSection += `- **Database**: ${resolvedDatabase}
64538
64867
  `;
64539
- }
64540
- if (language || queryName || database) {
64868
+ }
64541
64869
  contextSection += "\n";
64542
- }
64543
- return {
64544
- messages: [
64545
- {
64546
- role: "user",
64547
- content: {
64548
- type: "text",
64549
- text: contextSection + template
64870
+ const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
64871
+ return {
64872
+ messages: [
64873
+ {
64874
+ role: "user",
64875
+ content: {
64876
+ type: "text",
64877
+ text: warningSection + contextSection + template
64878
+ }
64550
64879
  }
64551
- }
64552
- ]
64553
- };
64554
- }
64880
+ ]
64881
+ };
64882
+ }
64883
+ )
64555
64884
  );
64556
64885
  server.prompt(
64557
64886
  "sarif_rank_false_positives",
64558
64887
  "Analyze SARIF results to identify likely false positives in CodeQL query results",
64559
- sarifRankSchema.shape,
64560
- async ({ queryId, sarifPath }) => {
64561
- const template = loadPromptTemplate("sarif-rank-false-positives.prompt.md");
64562
- let contextSection = "## Analysis Context\n\n";
64563
- if (queryId) {
64564
- contextSection += `- **Query ID**: ${queryId}
64888
+ toPermissiveShape(sarifRankSchema.shape),
64889
+ createSafePromptHandler(
64890
+ "sarif_rank_false_positives",
64891
+ sarifRankSchema,
64892
+ async ({ queryId, sarifPath }) => {
64893
+ const template = loadPromptTemplate("sarif-rank-false-positives.prompt.md");
64894
+ const warnings = [];
64895
+ const spResult = await resolvePromptFilePath(sarifPath);
64896
+ if (spResult.blocked) return blockedPathError(spResult, "SARIF path");
64897
+ const resolvedSarifPath = spResult.resolvedPath;
64898
+ if (spResult.warning) warnings.push(spResult.warning);
64899
+ let contextSection = "## Analysis Context\n\n";
64900
+ if (queryId) {
64901
+ contextSection += `- **Query ID**: ${queryId}
64565
64902
  `;
64566
- }
64567
- if (sarifPath) {
64568
- contextSection += `- **SARIF File**: ${sarifPath}
64903
+ }
64904
+ contextSection += `- **SARIF File**: ${resolvedSarifPath}
64569
64905
  `;
64570
- }
64571
- if (queryId || sarifPath) {
64572
64906
  contextSection += "\n";
64573
- }
64574
- return {
64575
- messages: [
64576
- {
64577
- role: "user",
64578
- content: {
64579
- type: "text",
64580
- text: contextSection + template
64907
+ const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
64908
+ return {
64909
+ messages: [
64910
+ {
64911
+ role: "user",
64912
+ content: {
64913
+ type: "text",
64914
+ text: warningSection + contextSection + template
64915
+ }
64581
64916
  }
64582
- }
64583
- ]
64584
- };
64585
- }
64917
+ ]
64918
+ };
64919
+ }
64920
+ )
64586
64921
  );
64587
64922
  server.prompt(
64588
64923
  "sarif_rank_true_positives",
64589
64924
  "Analyze SARIF results to identify likely true positives in CodeQL query results",
64590
- sarifRankSchema.shape,
64591
- async ({ queryId, sarifPath }) => {
64592
- const template = loadPromptTemplate("sarif-rank-true-positives.prompt.md");
64593
- let contextSection = "## Analysis Context\n\n";
64594
- if (queryId) {
64595
- contextSection += `- **Query ID**: ${queryId}
64925
+ toPermissiveShape(sarifRankSchema.shape),
64926
+ createSafePromptHandler(
64927
+ "sarif_rank_true_positives",
64928
+ sarifRankSchema,
64929
+ async ({ queryId, sarifPath }) => {
64930
+ const template = loadPromptTemplate("sarif-rank-true-positives.prompt.md");
64931
+ const warnings = [];
64932
+ const spResult = await resolvePromptFilePath(sarifPath);
64933
+ if (spResult.blocked) return blockedPathError(spResult, "SARIF path");
64934
+ const resolvedSarifPath = spResult.resolvedPath;
64935
+ if (spResult.warning) warnings.push(spResult.warning);
64936
+ let contextSection = "## Analysis Context\n\n";
64937
+ if (queryId) {
64938
+ contextSection += `- **Query ID**: ${queryId}
64596
64939
  `;
64597
- }
64598
- if (sarifPath) {
64599
- contextSection += `- **SARIF File**: ${sarifPath}
64940
+ }
64941
+ contextSection += `- **SARIF File**: ${resolvedSarifPath}
64600
64942
  `;
64601
- }
64602
- if (queryId || sarifPath) {
64603
64943
  contextSection += "\n";
64604
- }
64605
- return {
64606
- messages: [
64607
- {
64608
- role: "user",
64609
- content: {
64610
- type: "text",
64611
- text: contextSection + template
64944
+ const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
64945
+ return {
64946
+ messages: [
64947
+ {
64948
+ role: "user",
64949
+ content: {
64950
+ type: "text",
64951
+ text: warningSection + contextSection + template
64952
+ }
64612
64953
  }
64613
- }
64614
- ]
64615
- };
64616
- }
64954
+ ]
64955
+ };
64956
+ }
64957
+ )
64617
64958
  );
64618
64959
  server.prompt(
64619
64960
  "run_query_and_summarize_false_positives",
64620
64961
  "Help a user figure out where their query may need improvement to have a lower false positive rate",
64621
- describeFalsePositivesSchema.shape,
64622
- async ({ queryPath }) => {
64623
- const template = loadPromptTemplate("run-query-and-summarize-false-positives.prompt.md");
64624
- let contextSection = "## Analysis Context\n\n";
64625
- if (queryPath) {
64626
- contextSection += `- **Query Path**: ${queryPath}
64962
+ toPermissiveShape(describeFalsePositivesSchema.shape),
64963
+ createSafePromptHandler(
64964
+ "run_query_and_summarize_false_positives",
64965
+ describeFalsePositivesSchema,
64966
+ async ({ queryPath }) => {
64967
+ const template = loadPromptTemplate("run-query-and-summarize-false-positives.prompt.md");
64968
+ const warnings = [];
64969
+ const qpResult = await resolvePromptFilePath(queryPath);
64970
+ if (qpResult.blocked) return blockedPathError(qpResult, "query path");
64971
+ const resolvedQueryPath = qpResult.resolvedPath;
64972
+ if (qpResult.warning) warnings.push(qpResult.warning);
64973
+ const contextSection = `## Analysis Context
64974
+
64975
+ - **Query Path**: ${resolvedQueryPath}
64976
+
64627
64977
  `;
64628
- }
64629
- contextSection += "\n";
64630
- return {
64631
- messages: [
64632
- {
64633
- role: "user",
64634
- content: {
64635
- type: "text",
64636
- text: contextSection + template
64978
+ const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
64979
+ return {
64980
+ messages: [
64981
+ {
64982
+ role: "user",
64983
+ content: {
64984
+ type: "text",
64985
+ text: warningSection + contextSection + template
64986
+ }
64637
64987
  }
64638
- }
64639
- ]
64640
- };
64641
- }
64988
+ ]
64989
+ };
64990
+ }
64991
+ )
64642
64992
  );
64643
64993
  server.prompt(
64644
64994
  "explain_codeql_query",
64645
64995
  "Generate detailed explanation of a CodeQL query for workshop learning content - uses MCP tools to gather context and produces both verbal explanations and mermaid evaluation diagrams",
64646
- explainCodeqlQuerySchema.shape,
64647
- async ({ queryPath, language, databasePath }) => {
64648
- const template = loadPromptTemplate("explain-codeql-query.prompt.md");
64649
- let contextSection = "## Query to Explain\n\n";
64650
- contextSection += `- **Query Path**: ${queryPath}
64996
+ toPermissiveShape(explainCodeqlQuerySchema.shape),
64997
+ createSafePromptHandler(
64998
+ "explain_codeql_query",
64999
+ explainCodeqlQuerySchema,
65000
+ async ({ queryPath, language, databasePath }) => {
65001
+ const template = loadPromptTemplate("explain-codeql-query.prompt.md");
65002
+ const warnings = [];
65003
+ const qpResult = await resolvePromptFilePath(queryPath);
65004
+ if (qpResult.blocked) return blockedPathError(qpResult, "query path");
65005
+ const resolvedQueryPath = qpResult.resolvedPath;
65006
+ if (qpResult.warning) warnings.push(qpResult.warning);
65007
+ let resolvedDatabasePath = databasePath;
65008
+ if (databasePath) {
65009
+ const dbResult = await resolvePromptFilePath(databasePath);
65010
+ if (dbResult.blocked) return blockedPathError(dbResult, "database path");
65011
+ resolvedDatabasePath = dbResult.resolvedPath;
65012
+ if (dbResult.warning) warnings.push(dbResult.warning);
65013
+ }
65014
+ let contextSection = "## Query to Explain\n\n";
65015
+ contextSection += `- **Query Path**: ${resolvedQueryPath}
64651
65016
  `;
64652
- contextSection += `- **Language**: ${language}
65017
+ contextSection += `- **Language**: ${language}
64653
65018
  `;
64654
- if (databasePath) {
64655
- contextSection += `- **Database Path**: ${databasePath}
65019
+ if (resolvedDatabasePath) {
65020
+ contextSection += `- **Database Path**: ${resolvedDatabasePath}
64656
65021
  `;
65022
+ }
65023
+ contextSection += "\n";
65024
+ const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
65025
+ return {
65026
+ messages: [
65027
+ {
65028
+ role: "user",
65029
+ content: {
65030
+ type: "text",
65031
+ text: warningSection + contextSection + template
65032
+ }
65033
+ }
65034
+ ]
65035
+ };
64657
65036
  }
64658
- contextSection += "\n";
65037
+ )
65038
+ );
65039
+ server.prompt(
65040
+ "document_codeql_query",
65041
+ "Create or update documentation for a CodeQL query - generates standardized markdown documentation as a sibling file to the query",
65042
+ toPermissiveShape(documentCodeqlQuerySchema.shape),
65043
+ createSafePromptHandler(
65044
+ "document_codeql_query",
65045
+ documentCodeqlQuerySchema,
65046
+ async ({ queryPath, language }) => {
65047
+ const template = loadPromptTemplate("document-codeql-query.prompt.md");
65048
+ const warnings = [];
65049
+ const qpResult = await resolvePromptFilePath(queryPath);
65050
+ if (qpResult.blocked) return blockedPathError(qpResult, "query path");
65051
+ const resolvedQueryPath = qpResult.resolvedPath;
65052
+ if (qpResult.warning) warnings.push(qpResult.warning);
65053
+ const contextSection = `## Query to Document
65054
+
65055
+ - **Query Path**: ${resolvedQueryPath}
65056
+ - **Language**: ${language}
65057
+
65058
+ `;
65059
+ const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
65060
+ return {
65061
+ messages: [
65062
+ {
65063
+ role: "user",
65064
+ content: {
65065
+ type: "text",
65066
+ text: warningSection + contextSection + template
65067
+ }
65068
+ }
65069
+ ]
65070
+ };
65071
+ }
65072
+ )
65073
+ );
65074
+ server.prompt(
65075
+ "check_for_duplicated_code",
65076
+ "Check a .ql or .qll file for classes, predicates, and modules that duplicate definitions already available in the standard CodeQL libraries or shared project .qll files",
65077
+ checkForDuplicatedCodeSchema.shape,
65078
+ async ({ queryPath, workspaceUri }) => {
65079
+ const template = loadPromptTemplate("check-for-duplicated-code.prompt.md");
65080
+ const contextSection = `## File to Audit
65081
+
65082
+ - **Query Path**: ${queryPath}
65083
+ ${workspaceUri ? `- **Workspace URI**: ${workspaceUri}
65084
+ ` : ""}
65085
+ `;
64659
65086
  return {
64660
65087
  messages: [
64661
65088
  {
@@ -64670,24 +65097,24 @@ ${content}`
64670
65097
  }
64671
65098
  );
64672
65099
  server.prompt(
64673
- "document_codeql_query",
64674
- "Create or update documentation for a CodeQL query - generates standardized markdown documentation as a sibling file to the query",
64675
- documentCodeqlQuerySchema.shape,
64676
- async ({ queryPath, language }) => {
64677
- const template = loadPromptTemplate("document-codeql-query.prompt.md");
64678
- const contextSection = `## Query to Document
64679
-
64680
- - **Query Path**: ${queryPath}
65100
+ "find_overlapping_queries",
65101
+ "Discover existing .ql query files and .qll library files whose content may overlap with a new query design, identifying reusable classes, predicates, and modules",
65102
+ findOverlappingQueriesSchema.shape,
65103
+ async ({ queryDescription, language, packRoot }) => {
65104
+ const template = loadPromptTemplate("find-overlapping-queries.prompt.md");
65105
+ const contextSection = `## New Query Context
65106
+
65107
+ - **Query Description**: ${queryDescription}
64681
65108
  - **Language**: ${language}
64682
-
64683
- `;
65109
+ ` + (packRoot ? `- **Pack Root**: ${packRoot}
65110
+ ` : "");
64684
65111
  return {
64685
65112
  messages: [
64686
65113
  {
64687
65114
  role: "user",
64688
65115
  content: {
64689
65116
  type: "text",
64690
- text: contextSection + template
65117
+ text: contextSection + "\n" + template
64691
65118
  }
64692
65119
  }
64693
65120
  ]
@@ -64697,37 +65124,48 @@ ${content}`
64697
65124
  server.prompt(
64698
65125
  "ql_lsp_iterative_development",
64699
65126
  "Iterative CodeQL query development using LSP tools for completion, navigation, and validation",
64700
- qlLspIterativeDevelopmentSchema.shape,
64701
- async ({ language, queryPath, workspaceUri }) => {
64702
- const template = loadPromptTemplate("ql-lsp-iterative-development.prompt.md");
64703
- let contextSection = "## Your Development Context\n\n";
64704
- if (language) {
65127
+ toPermissiveShape(qlLspIterativeDevelopmentSchema.shape),
65128
+ createSafePromptHandler(
65129
+ "ql_lsp_iterative_development",
65130
+ qlLspIterativeDevelopmentSchema,
65131
+ async ({ language, queryPath, workspaceUri }) => {
65132
+ const template = loadPromptTemplate("ql-lsp-iterative-development.prompt.md");
65133
+ const warnings = [];
65134
+ const qpResult = await resolvePromptFilePath(queryPath);
65135
+ if (qpResult.blocked) return blockedPathError(qpResult, "query path");
65136
+ const resolvedQueryPath = qpResult.resolvedPath;
65137
+ if (qpResult.warning) warnings.push(qpResult.warning);
65138
+ let resolvedWorkspaceUri = workspaceUri;
65139
+ if (workspaceUri) {
65140
+ const wsResult = await resolvePromptFilePath(workspaceUri);
65141
+ if (wsResult.blocked) return blockedPathError(wsResult, "workspace URI");
65142
+ resolvedWorkspaceUri = wsResult.resolvedPath;
65143
+ if (wsResult.warning) warnings.push(wsResult.warning);
65144
+ }
65145
+ let contextSection = "## Your Development Context\n\n";
64705
65146
  contextSection += `- **Language**: ${language}
64706
65147
  `;
64707
- }
64708
- if (queryPath) {
64709
- contextSection += `- **Query Path**: ${queryPath}
65148
+ contextSection += `- **Query Path**: ${resolvedQueryPath}
64710
65149
  `;
64711
- }
64712
- if (workspaceUri) {
64713
- contextSection += `- **Workspace URI**: ${workspaceUri}
65150
+ if (resolvedWorkspaceUri) {
65151
+ contextSection += `- **Workspace URI**: ${resolvedWorkspaceUri}
64714
65152
  `;
64715
- }
64716
- if (language || queryPath || workspaceUri) {
65153
+ }
64717
65154
  contextSection += "\n";
64718
- }
64719
- return {
64720
- messages: [
64721
- {
64722
- role: "user",
64723
- content: {
64724
- type: "text",
64725
- text: contextSection + template
65155
+ const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
65156
+ return {
65157
+ messages: [
65158
+ {
65159
+ role: "user",
65160
+ content: {
65161
+ type: "text",
65162
+ text: warningSection + contextSection + template
65163
+ }
64726
65164
  }
64727
- }
64728
- ]
64729
- };
64730
- }
65165
+ ]
65166
+ };
65167
+ }
65168
+ )
64731
65169
  );
64732
65170
  logger.info(`Registered ${WORKFLOW_PROMPT_NAMES.length} workflow prompts`);
64733
65171
  }
@@ -66186,9 +66624,9 @@ init_cli_executor();
66186
66624
  init_server_manager();
66187
66625
  init_package_paths();
66188
66626
  init_logger();
66189
- import_dotenv.default.config({ path: resolve13(packageRootDir, ".env"), quiet: true });
66627
+ import_dotenv.default.config({ path: resolve14(packageRootDir, ".env"), quiet: true });
66190
66628
  var PACKAGE_NAME = "codeql-development-mcp-server";
66191
- var VERSION = "2.24.3-rc2";
66629
+ var VERSION = "2.25.0-rc1";
66192
66630
  async function startServer(mode = "stdio") {
66193
66631
  logger.info(`Starting CodeQL Development MCP McpServer v${VERSION} in ${mode} mode`);
66194
66632
  const codeqlBinary = resolveCodeQLBinary();
@@ -66242,10 +66680,10 @@ async function startServer(mode = "stdio") {
66242
66680
  });
66243
66681
  const host = process.env.HTTP_HOST || "localhost";
66244
66682
  const port = Number(process.env.HTTP_PORT || process.env.PORT) || 3e3;
66245
- return new Promise((resolve14, reject) => {
66683
+ return new Promise((resolve15, reject) => {
66246
66684
  const httpServer = app.listen(port, host, () => {
66247
66685
  logger.info(`HTTP server listening on http://${host}:${port}/mcp`);
66248
- resolve14();
66686
+ resolve15();
66249
66687
  });
66250
66688
  httpServer.on("error", (error2) => {
66251
66689
  logger.error("HTTP server error:", error2);
@@ -66282,7 +66720,7 @@ async function main() {
66282
66720
  process.exit(1);
66283
66721
  }
66284
66722
  }
66285
- var scriptPath = process.argv[1] ? realpathSync2(resolve13(process.argv[1])) : void 0;
66723
+ var scriptPath = process.argv[1] ? realpathSync2(resolve14(process.argv[1])) : void 0;
66286
66724
  if (scriptPath && import.meta.url === pathToFileURL5(scriptPath).href) {
66287
66725
  main();
66288
66726
  }