codeql-development-mcp-server 2.24.3-rc1 → 2.24.3-rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/codeql-development-mcp-server.js +835 -417
- package/dist/codeql-development-mcp-server.js.map +4 -4
- package/package.json +1 -1
- package/ql/actions/tools/src/codeql-pack.yml +1 -1
- package/ql/cpp/tools/src/codeql-pack.yml +1 -1
- package/ql/csharp/tools/src/codeql-pack.yml +1 -1
- package/ql/go/tools/src/codeql-pack.yml +1 -1
- package/ql/java/tools/src/codeql-pack.yml +1 -1
- package/ql/javascript/tools/src/codeql-pack.yml +1 -1
- package/ql/python/tools/src/codeql-pack.yml +1 -1
- package/ql/ruby/tools/src/codeql-pack.yml +1 -1
- package/ql/swift/tools/src/codeql-pack.yml +1 -1
|
@@ -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 =
|
|
2994
|
+
let _sch = resolve14.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
|
|
3021
|
+
function resolve14(root, ref) {
|
|
3022
3022
|
let sch;
|
|
3023
3023
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3024
3024
|
ref = sch;
|
|
@@ -3593,7 +3593,7 @@ var require_fast_uri = __commonJS({
|
|
|
3593
3593
|
}
|
|
3594
3594
|
return uri;
|
|
3595
3595
|
}
|
|
3596
|
-
function
|
|
3596
|
+
function resolve14(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;
|
|
@@ -3820,7 +3820,7 @@ var require_fast_uri = __commonJS({
|
|
|
3820
3820
|
var fastUri = {
|
|
3821
3821
|
SCHEMES,
|
|
3822
3822
|
normalize,
|
|
3823
|
-
resolve:
|
|
3823
|
+
resolve: resolve14,
|
|
3824
3824
|
resolveComponent,
|
|
3825
3825
|
equal,
|
|
3826
3826
|
serialize,
|
|
@@ -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 =
|
|
9614
|
+
let _sch = resolve14.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
|
|
9641
|
+
function resolve14(root, ref) {
|
|
9642
9642
|
let sch;
|
|
9643
9643
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
9644
9644
|
ref = sch;
|
|
@@ -12713,8 +12713,8 @@ var require_common = __commonJS({
|
|
|
12713
12713
|
}
|
|
12714
12714
|
return debug;
|
|
12715
12715
|
}
|
|
12716
|
-
function extend4(namespace,
|
|
12717
|
-
const newDebug = createDebug(this.namespace + (typeof
|
|
12716
|
+
function extend4(namespace, delimiter6) {
|
|
12717
|
+
const newDebug = createDebug(this.namespace + (typeof delimiter6 === "undefined" ? ":" : delimiter6) + namespace);
|
|
12718
12718
|
newDebug.log = this.log;
|
|
12719
12719
|
return newDebug;
|
|
12720
12720
|
}
|
|
@@ -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(
|
|
17922
|
+
return new Promise(function executor(resolve14, reject) {
|
|
17923
17923
|
readStream(stream, encoding, length, limit, function onRead(err, buf) {
|
|
17924
17924
|
if (err) return reject(err);
|
|
17925
|
-
|
|
17925
|
+
resolve14(buf);
|
|
17926
17926
|
});
|
|
17927
17927
|
});
|
|
17928
17928
|
}
|
|
@@ -27724,7 +27724,7 @@ var require_mime_types = __commonJS({
|
|
|
27724
27724
|
"../node_modules/mime-types/index.js"(exports) {
|
|
27725
27725
|
"use strict";
|
|
27726
27726
|
var db = require_mime_db();
|
|
27727
|
-
var
|
|
27727
|
+
var extname3 = __require("path").extname;
|
|
27728
27728
|
var mimeScore = require_mimeScore();
|
|
27729
27729
|
var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/;
|
|
27730
27730
|
var TEXT_TYPE_REGEXP = /^text\//i;
|
|
@@ -27780,7 +27780,7 @@ var require_mime_types = __commonJS({
|
|
|
27780
27780
|
if (!path4 || typeof path4 !== "string") {
|
|
27781
27781
|
return false;
|
|
27782
27782
|
}
|
|
27783
|
-
var extension2 =
|
|
27783
|
+
var extension2 = extname3("x." + path4).toLowerCase().slice(1);
|
|
27784
27784
|
if (!extension2) {
|
|
27785
27785
|
return false;
|
|
27786
27786
|
}
|
|
@@ -31255,15 +31255,15 @@ var require_view = __commonJS({
|
|
|
31255
31255
|
var path4 = __require("node:path");
|
|
31256
31256
|
var fs3 = __require("node:fs");
|
|
31257
31257
|
var dirname8 = path4.dirname;
|
|
31258
|
-
var
|
|
31259
|
-
var
|
|
31260
|
-
var
|
|
31261
|
-
var
|
|
31258
|
+
var basename8 = path4.basename;
|
|
31259
|
+
var extname3 = path4.extname;
|
|
31260
|
+
var join19 = path4.join;
|
|
31261
|
+
var resolve14 = path4.resolve;
|
|
31262
31262
|
module.exports = View;
|
|
31263
31263
|
function View(name, options) {
|
|
31264
31264
|
var opts = options || {};
|
|
31265
31265
|
this.defaultEngine = opts.defaultEngine;
|
|
31266
|
-
this.ext =
|
|
31266
|
+
this.ext = extname3(name);
|
|
31267
31267
|
this.name = name;
|
|
31268
31268
|
this.root = opts.root;
|
|
31269
31269
|
if (!this.ext && !this.defaultEngine) {
|
|
@@ -31292,9 +31292,9 @@ 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 =
|
|
31295
|
+
var loc = resolve14(root, name);
|
|
31296
31296
|
var dir = dirname8(loc);
|
|
31297
|
-
var file =
|
|
31297
|
+
var file = basename8(loc);
|
|
31298
31298
|
path5 = this.resolve(dir, file);
|
|
31299
31299
|
}
|
|
31300
31300
|
return path5;
|
|
@@ -31317,14 +31317,14 @@ var require_view = __commonJS({
|
|
|
31317
31317
|
});
|
|
31318
31318
|
sync = false;
|
|
31319
31319
|
};
|
|
31320
|
-
View.prototype.resolve = function
|
|
31320
|
+
View.prototype.resolve = function resolve15(dir, file) {
|
|
31321
31321
|
var ext = this.ext;
|
|
31322
|
-
var path5 =
|
|
31322
|
+
var path5 = join19(dir, file);
|
|
31323
31323
|
var stat = tryStat(path5);
|
|
31324
31324
|
if (stat && stat.isFile()) {
|
|
31325
31325
|
return path5;
|
|
31326
31326
|
}
|
|
31327
|
-
path5 =
|
|
31327
|
+
path5 = join19(dir, basename8(file, ext), "index" + ext);
|
|
31328
31328
|
stat = tryStat(path5);
|
|
31329
31329
|
if (stat && stat.isFile()) {
|
|
31330
31330
|
return path5;
|
|
@@ -32564,9 +32564,9 @@ var require_dist2 = __commonJS({
|
|
|
32564
32564
|
return new TokenData(consumeUntil("end"), str2);
|
|
32565
32565
|
}
|
|
32566
32566
|
function compile(path4, options = {}) {
|
|
32567
|
-
const { encode = encodeURIComponent, delimiter:
|
|
32567
|
+
const { encode = encodeURIComponent, delimiter: delimiter6 = DEFAULT_DELIMITER } = options;
|
|
32568
32568
|
const data = typeof path4 === "object" ? path4 : parse4(path4, options);
|
|
32569
|
-
const fn = tokensToFunction(data.tokens,
|
|
32569
|
+
const fn = tokensToFunction(data.tokens, delimiter6, encode);
|
|
32570
32570
|
return function path5(params = {}) {
|
|
32571
32571
|
const [path6, ...missing] = fn(params);
|
|
32572
32572
|
if (missing.length) {
|
|
@@ -32575,8 +32575,8 @@ var require_dist2 = __commonJS({
|
|
|
32575
32575
|
return path6;
|
|
32576
32576
|
};
|
|
32577
32577
|
}
|
|
32578
|
-
function tokensToFunction(tokens,
|
|
32579
|
-
const encoders = tokens.map((token) => tokenToFunction(token,
|
|
32578
|
+
function tokensToFunction(tokens, delimiter6, encode) {
|
|
32579
|
+
const encoders = tokens.map((token) => tokenToFunction(token, delimiter6, encode));
|
|
32580
32580
|
return (data) => {
|
|
32581
32581
|
const result = [""];
|
|
32582
32582
|
for (const encoder of encoders) {
|
|
@@ -32587,11 +32587,11 @@ var require_dist2 = __commonJS({
|
|
|
32587
32587
|
return result;
|
|
32588
32588
|
};
|
|
32589
32589
|
}
|
|
32590
|
-
function tokenToFunction(token,
|
|
32590
|
+
function tokenToFunction(token, delimiter6, encode) {
|
|
32591
32591
|
if (token.type === "text")
|
|
32592
32592
|
return () => [token.value];
|
|
32593
32593
|
if (token.type === "group") {
|
|
32594
|
-
const fn = tokensToFunction(token.tokens,
|
|
32594
|
+
const fn = tokensToFunction(token.tokens, delimiter6, encode);
|
|
32595
32595
|
return (data) => {
|
|
32596
32596
|
const [value, ...missing] = fn(data);
|
|
32597
32597
|
if (!missing.length)
|
|
@@ -32614,7 +32614,7 @@ var require_dist2 = __commonJS({
|
|
|
32614
32614
|
throw new TypeError(`Expected "${token.name}/${index}" to be a string`);
|
|
32615
32615
|
}
|
|
32616
32616
|
return encodeValue(value2);
|
|
32617
|
-
}).join(
|
|
32617
|
+
}).join(delimiter6)
|
|
32618
32618
|
];
|
|
32619
32619
|
};
|
|
32620
32620
|
}
|
|
@@ -32629,14 +32629,14 @@ var require_dist2 = __commonJS({
|
|
|
32629
32629
|
};
|
|
32630
32630
|
}
|
|
32631
32631
|
function match(path4, options = {}) {
|
|
32632
|
-
const { decode = decodeURIComponent, delimiter:
|
|
32632
|
+
const { decode = decodeURIComponent, delimiter: delimiter6 = DEFAULT_DELIMITER } = options;
|
|
32633
32633
|
const { regexp, keys } = pathToRegexp(path4, options);
|
|
32634
32634
|
const decoders = keys.map((key) => {
|
|
32635
32635
|
if (decode === false)
|
|
32636
32636
|
return NOOP_VALUE;
|
|
32637
32637
|
if (key.type === "param")
|
|
32638
32638
|
return decode;
|
|
32639
|
-
return (value) => value.split(
|
|
32639
|
+
return (value) => value.split(delimiter6).map(decode);
|
|
32640
32640
|
});
|
|
32641
32641
|
return function match2(input) {
|
|
32642
32642
|
const m = regexp.exec(input);
|
|
@@ -32655,20 +32655,20 @@ var require_dist2 = __commonJS({
|
|
|
32655
32655
|
};
|
|
32656
32656
|
}
|
|
32657
32657
|
function pathToRegexp(path4, options = {}) {
|
|
32658
|
-
const { delimiter:
|
|
32658
|
+
const { delimiter: delimiter6 = DEFAULT_DELIMITER, end = true, sensitive = false, trailing = true } = options;
|
|
32659
32659
|
const keys = [];
|
|
32660
32660
|
const flags = sensitive ? "" : "i";
|
|
32661
32661
|
const sources = [];
|
|
32662
32662
|
for (const input of pathsToArray(path4, [])) {
|
|
32663
32663
|
const data = typeof input === "object" ? input : parse4(input, options);
|
|
32664
32664
|
for (const tokens of flatten(data.tokens, 0, [])) {
|
|
32665
|
-
sources.push(toRegExpSource(tokens,
|
|
32665
|
+
sources.push(toRegExpSource(tokens, delimiter6, keys, data.originalPath));
|
|
32666
32666
|
}
|
|
32667
32667
|
}
|
|
32668
32668
|
let pattern = `^(?:${sources.join("|")})`;
|
|
32669
32669
|
if (trailing)
|
|
32670
|
-
pattern += `(?:${escape2(
|
|
32671
|
-
pattern += end ? "$" : `(?=${escape2(
|
|
32670
|
+
pattern += `(?:${escape2(delimiter6)}$)?`;
|
|
32671
|
+
pattern += end ? "$" : `(?=${escape2(delimiter6)}|$)`;
|
|
32672
32672
|
const regexp = new RegExp(pattern, flags);
|
|
32673
32673
|
return { regexp, keys };
|
|
32674
32674
|
}
|
|
@@ -32695,7 +32695,7 @@ var require_dist2 = __commonJS({
|
|
|
32695
32695
|
}
|
|
32696
32696
|
yield* flatten(tokens, index + 1, init);
|
|
32697
32697
|
}
|
|
32698
|
-
function toRegExpSource(tokens,
|
|
32698
|
+
function toRegExpSource(tokens, delimiter6, keys, originalPath) {
|
|
32699
32699
|
let result = "";
|
|
32700
32700
|
let backtrack = "";
|
|
32701
32701
|
let isSafeSegmentParam = true;
|
|
@@ -32703,7 +32703,7 @@ var require_dist2 = __commonJS({
|
|
|
32703
32703
|
if (token.type === "text") {
|
|
32704
32704
|
result += escape2(token.value);
|
|
32705
32705
|
backtrack += token.value;
|
|
32706
|
-
isSafeSegmentParam || (isSafeSegmentParam = token.value.includes(
|
|
32706
|
+
isSafeSegmentParam || (isSafeSegmentParam = token.value.includes(delimiter6));
|
|
32707
32707
|
continue;
|
|
32708
32708
|
}
|
|
32709
32709
|
if (token.type === "param" || token.type === "wildcard") {
|
|
@@ -32711,7 +32711,7 @@ var require_dist2 = __commonJS({
|
|
|
32711
32711
|
throw new PathError(`Missing text before "${token.name}" ${token.type}`, originalPath);
|
|
32712
32712
|
}
|
|
32713
32713
|
if (token.type === "param") {
|
|
32714
|
-
result += `(${negate(
|
|
32714
|
+
result += `(${negate(delimiter6, isSafeSegmentParam ? "" : backtrack)}+)`;
|
|
32715
32715
|
} else {
|
|
32716
32716
|
result += `([\\s\\S]+)`;
|
|
32717
32717
|
}
|
|
@@ -32723,16 +32723,16 @@ var require_dist2 = __commonJS({
|
|
|
32723
32723
|
}
|
|
32724
32724
|
return result;
|
|
32725
32725
|
}
|
|
32726
|
-
function negate(
|
|
32726
|
+
function negate(delimiter6, backtrack) {
|
|
32727
32727
|
if (backtrack.length < 2) {
|
|
32728
|
-
if (
|
|
32729
|
-
return `[^${escape2(
|
|
32730
|
-
return `(?:(?!${escape2(
|
|
32728
|
+
if (delimiter6.length < 2)
|
|
32729
|
+
return `[^${escape2(delimiter6 + backtrack)}]`;
|
|
32730
|
+
return `(?:(?!${escape2(delimiter6)})[^${escape2(backtrack)}])`;
|
|
32731
32731
|
}
|
|
32732
|
-
if (
|
|
32733
|
-
return `(?:(?!${escape2(backtrack)})[^${escape2(
|
|
32732
|
+
if (delimiter6.length < 2) {
|
|
32733
|
+
return `(?:(?!${escape2(backtrack)})[^${escape2(delimiter6)}])`;
|
|
32734
32734
|
}
|
|
32735
|
-
return `(?:(?!${escape2(backtrack)}|${escape2(
|
|
32735
|
+
return `(?:(?!${escape2(backtrack)}|${escape2(delimiter6)})[\\s\\S])`;
|
|
32736
32736
|
}
|
|
32737
32737
|
function stringifyTokens(tokens) {
|
|
32738
32738
|
let value = "";
|
|
@@ -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
|
|
33461
|
+
var resolve14 = __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",
|
|
33515
|
+
this.set("views", resolve14("views"));
|
|
33516
33516
|
this.set("jsonp callback name", "callback");
|
|
33517
33517
|
if (env === "production") {
|
|
33518
33518
|
this.enable("view cache");
|
|
@@ -34608,7 +34608,7 @@ var require_content_disposition = __commonJS({
|
|
|
34608
34608
|
"use strict";
|
|
34609
34609
|
module.exports = contentDisposition;
|
|
34610
34610
|
module.exports.parse = parse4;
|
|
34611
|
-
var
|
|
34611
|
+
var basename8 = __require("path").basename;
|
|
34612
34612
|
var ENCODE_URL_ATTR_CHAR_REGEXP = /[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g;
|
|
34613
34613
|
var HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/;
|
|
34614
34614
|
var HEX_ESCAPE_REPLACE_REGEXP = /%([0-9A-Fa-f]{2})/g;
|
|
@@ -34643,9 +34643,9 @@ var require_content_disposition = __commonJS({
|
|
|
34643
34643
|
if (typeof fallback === "string" && NON_LATIN1_REGEXP.test(fallback)) {
|
|
34644
34644
|
throw new TypeError("fallback must be ISO-8859-1 string");
|
|
34645
34645
|
}
|
|
34646
|
-
var name =
|
|
34646
|
+
var name = basename8(filename);
|
|
34647
34647
|
var isQuotedString = TEXT_REGEXP.test(name);
|
|
34648
|
-
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) :
|
|
34648
|
+
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) : basename8(fallback);
|
|
34649
34649
|
var hasFallback = typeof fallbackName === "string" && fallbackName !== name;
|
|
34650
34650
|
if (hasFallback || !isQuotedString || HEX_ESCAPE_REGEXP.test(name)) {
|
|
34651
34651
|
params["filename*"] = name;
|
|
@@ -34968,10 +34968,10 @@ var require_send = __commonJS({
|
|
|
34968
34968
|
var statuses = require_statuses();
|
|
34969
34969
|
var Stream = __require("stream");
|
|
34970
34970
|
var util2 = __require("util");
|
|
34971
|
-
var
|
|
34972
|
-
var
|
|
34971
|
+
var extname3 = path4.extname;
|
|
34972
|
+
var join19 = path4.join;
|
|
34973
34973
|
var normalize = path4.normalize;
|
|
34974
|
-
var
|
|
34974
|
+
var resolve14 = path4.resolve;
|
|
34975
34975
|
var sep2 = path4.sep;
|
|
34976
34976
|
var BYTES_RANGE_REGEXP = /^ *bytes=/;
|
|
34977
34977
|
var MAX_MAXAGE = 60 * 60 * 24 * 365 * 1e3;
|
|
@@ -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 ?
|
|
35003
|
+
this._root = opts.root ? resolve14(opts.root) : null;
|
|
35004
35004
|
}
|
|
35005
35005
|
util2.inherits(SendStream, Stream);
|
|
35006
35006
|
SendStream.prototype.error = function error2(status, err) {
|
|
@@ -35141,7 +35141,7 @@ var require_send = __commonJS({
|
|
|
35141
35141
|
return res;
|
|
35142
35142
|
}
|
|
35143
35143
|
parts = path5.split(sep2);
|
|
35144
|
-
path5 = normalize(
|
|
35144
|
+
path5 = normalize(join19(root, path5));
|
|
35145
35145
|
} else {
|
|
35146
35146
|
if (UP_PATH_REGEXP.test(path5)) {
|
|
35147
35147
|
debug('malicious path "%s"', path5);
|
|
@@ -35149,7 +35149,7 @@ var require_send = __commonJS({
|
|
|
35149
35149
|
return res;
|
|
35150
35150
|
}
|
|
35151
35151
|
parts = normalize(path5).split(sep2);
|
|
35152
|
-
path5 =
|
|
35152
|
+
path5 = resolve14(path5);
|
|
35153
35153
|
}
|
|
35154
35154
|
if (containsDotFile(parts)) {
|
|
35155
35155
|
debug('%s dotfile "%s"', this._dotfiles, path5);
|
|
@@ -35243,7 +35243,7 @@ var require_send = __commonJS({
|
|
|
35243
35243
|
debug('stat "%s"', path5);
|
|
35244
35244
|
fs3.stat(path5, function onstat(err, stat) {
|
|
35245
35245
|
var pathEndsWithSep = path5[path5.length - 1] === sep2;
|
|
35246
|
-
if (err && err.code === "ENOENT" && !
|
|
35246
|
+
if (err && err.code === "ENOENT" && !extname3(path5) && !pathEndsWithSep) {
|
|
35247
35247
|
return next(err);
|
|
35248
35248
|
}
|
|
35249
35249
|
if (err) return self.onStatError(err);
|
|
@@ -35274,7 +35274,7 @@ var require_send = __commonJS({
|
|
|
35274
35274
|
if (err) return self.onStatError(err);
|
|
35275
35275
|
return self.error(404);
|
|
35276
35276
|
}
|
|
35277
|
-
var p =
|
|
35277
|
+
var p = join19(path5, self._index[i]);
|
|
35278
35278
|
debug('stat "%s"', p);
|
|
35279
35279
|
fs3.stat(p, function(err2, stat) {
|
|
35280
35280
|
if (err2) return next(err2);
|
|
@@ -35306,7 +35306,7 @@ var require_send = __commonJS({
|
|
|
35306
35306
|
SendStream.prototype.type = function type2(path5) {
|
|
35307
35307
|
var res = this.res;
|
|
35308
35308
|
if (res.getHeader("Content-Type")) return;
|
|
35309
|
-
var ext =
|
|
35309
|
+
var ext = extname3(path5);
|
|
35310
35310
|
var type3 = mime.contentType(ext) || "application/octet-stream";
|
|
35311
35311
|
debug("content-type %s", type3);
|
|
35312
35312
|
res.setHeader("Content-Type", type3);
|
|
@@ -35526,8 +35526,8 @@ var require_response = __commonJS({
|
|
|
35526
35526
|
var setCharset = require_utils4().setCharset;
|
|
35527
35527
|
var cookie = require_cookie();
|
|
35528
35528
|
var send = require_send();
|
|
35529
|
-
var
|
|
35530
|
-
var
|
|
35529
|
+
var extname3 = path4.extname;
|
|
35530
|
+
var resolve14 = 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 ?
|
|
35736
|
+
var fullPath = !opts.root ? resolve14(path5) : path5;
|
|
35737
35737
|
return this.sendFile(fullPath, opts, done);
|
|
35738
35738
|
};
|
|
35739
35739
|
res.contentType = res.type = function contentType(type2) {
|
|
@@ -35764,7 +35764,7 @@ var require_response = __commonJS({
|
|
|
35764
35764
|
};
|
|
35765
35765
|
res.attachment = function attachment(filename) {
|
|
35766
35766
|
if (filename) {
|
|
35767
|
-
this.type(
|
|
35767
|
+
this.type(extname3(filename));
|
|
35768
35768
|
}
|
|
35769
35769
|
this.set("Content-Disposition", contentDisposition(filename));
|
|
35770
35770
|
return this;
|
|
@@ -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
|
|
35985
|
+
var resolve14 = __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 =
|
|
36004
|
+
opts.root = resolve14(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") {
|
|
@@ -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((
|
|
36995
|
+
return new Promise((resolve14, 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
|
-
|
|
37009
|
+
resolve14();
|
|
37010
37010
|
};
|
|
37011
37011
|
const onStdout = () => {
|
|
37012
37012
|
if (settled) return;
|
|
37013
37013
|
logger.debug(`${name}: ready (stdout output detected)`);
|
|
37014
37014
|
cleanup();
|
|
37015
|
-
|
|
37015
|
+
resolve14();
|
|
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
|
-
|
|
37031
|
+
resolve14();
|
|
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((
|
|
37199
|
+
return new Promise((resolve14, 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
|
-
|
|
37213
|
+
resolve14(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((
|
|
37302
|
+
return new Promise((resolve14, 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
|
-
|
|
37318
|
+
resolve14(params.diagnostics);
|
|
37319
37319
|
}
|
|
37320
37320
|
};
|
|
37321
37321
|
this.on("diagnostics", diagnosticsHandler);
|
|
@@ -37430,22 +37430,22 @@ var init_language_server = __esm({
|
|
|
37430
37430
|
} catch (error2) {
|
|
37431
37431
|
logger.warn("Error during graceful shutdown:", error2);
|
|
37432
37432
|
}
|
|
37433
|
-
await new Promise((
|
|
37433
|
+
await new Promise((resolve14) => {
|
|
37434
37434
|
const timer = setTimeout3(() => {
|
|
37435
37435
|
if (this.server) {
|
|
37436
37436
|
this.server.kill("SIGTERM");
|
|
37437
37437
|
}
|
|
37438
|
-
|
|
37438
|
+
resolve14();
|
|
37439
37439
|
}, 1e3);
|
|
37440
37440
|
if (this.server) {
|
|
37441
37441
|
this.server.once("exit", () => {
|
|
37442
37442
|
clearTimeout3(timer);
|
|
37443
37443
|
this.server = null;
|
|
37444
|
-
|
|
37444
|
+
resolve14();
|
|
37445
37445
|
});
|
|
37446
37446
|
} else {
|
|
37447
37447
|
clearTimeout3(timer);
|
|
37448
|
-
|
|
37448
|
+
resolve14();
|
|
37449
37449
|
}
|
|
37450
37450
|
});
|
|
37451
37451
|
this.isInitialized = false;
|
|
@@ -37535,8 +37535,8 @@ var init_query_server = __esm({
|
|
|
37535
37535
|
method,
|
|
37536
37536
|
params
|
|
37537
37537
|
};
|
|
37538
|
-
return new Promise((
|
|
37539
|
-
this.pendingRequests.set(id, { reject, resolve:
|
|
37538
|
+
return new Promise((resolve14, reject) => {
|
|
37539
|
+
this.pendingRequests.set(id, { reject, resolve: resolve14 });
|
|
37540
37540
|
try {
|
|
37541
37541
|
this.sendRaw(message);
|
|
37542
37542
|
} catch (error2) {
|
|
@@ -37550,7 +37550,7 @@ var init_query_server = __esm({
|
|
|
37550
37550
|
reject(new Error(`Query server request timeout for method: ${method}`));
|
|
37551
37551
|
}
|
|
37552
37552
|
}, timeoutMs);
|
|
37553
|
-
const originalResolve =
|
|
37553
|
+
const originalResolve = resolve14;
|
|
37554
37554
|
const originalReject = reject;
|
|
37555
37555
|
const wrapped = {
|
|
37556
37556
|
reject: (err) => {
|
|
@@ -37578,23 +37578,23 @@ var init_query_server = __esm({
|
|
|
37578
37578
|
} catch (error2) {
|
|
37579
37579
|
logger.warn("Error during query server graceful shutdown:", error2);
|
|
37580
37580
|
}
|
|
37581
|
-
await new Promise((
|
|
37581
|
+
await new Promise((resolve14) => {
|
|
37582
37582
|
const timer = setTimeout4(() => {
|
|
37583
37583
|
if (this.process) {
|
|
37584
37584
|
this.process.kill("SIGTERM");
|
|
37585
37585
|
this.process = null;
|
|
37586
37586
|
}
|
|
37587
|
-
|
|
37587
|
+
resolve14();
|
|
37588
37588
|
}, 2e3);
|
|
37589
37589
|
if (this.process) {
|
|
37590
37590
|
this.process.once("exit", () => {
|
|
37591
37591
|
clearTimeout4(timer);
|
|
37592
37592
|
this.process = null;
|
|
37593
|
-
|
|
37593
|
+
resolve14();
|
|
37594
37594
|
});
|
|
37595
37595
|
} else {
|
|
37596
37596
|
clearTimeout4(timer);
|
|
37597
|
-
|
|
37597
|
+
resolve14();
|
|
37598
37598
|
}
|
|
37599
37599
|
});
|
|
37600
37600
|
}
|
|
@@ -37755,9 +37755,9 @@ var init_cli_server = __esm({
|
|
|
37755
37755
|
* @returns The stdout output from the command.
|
|
37756
37756
|
*/
|
|
37757
37757
|
runCommand(args) {
|
|
37758
|
-
return new Promise((
|
|
37758
|
+
return new Promise((resolve14, reject) => {
|
|
37759
37759
|
const execute = () => {
|
|
37760
|
-
this.executeCommand({ args, reject, resolve:
|
|
37760
|
+
this.executeCommand({ args, reject, resolve: resolve14 });
|
|
37761
37761
|
};
|
|
37762
37762
|
if (this.commandInProgress) {
|
|
37763
37763
|
this.commandQueue.push(execute);
|
|
@@ -37780,23 +37780,23 @@ var init_cli_server = __esm({
|
|
|
37780
37780
|
} catch (error2) {
|
|
37781
37781
|
logger.warn("Error during CLI server shutdown request:", error2);
|
|
37782
37782
|
}
|
|
37783
|
-
await new Promise((
|
|
37783
|
+
await new Promise((resolve14) => {
|
|
37784
37784
|
const timer = setTimeout5(() => {
|
|
37785
37785
|
if (this.process) {
|
|
37786
37786
|
this.process.kill("SIGTERM");
|
|
37787
37787
|
this.process = null;
|
|
37788
37788
|
}
|
|
37789
|
-
|
|
37789
|
+
resolve14();
|
|
37790
37790
|
}, 2e3);
|
|
37791
37791
|
if (this.process) {
|
|
37792
37792
|
this.process.once("exit", () => {
|
|
37793
37793
|
clearTimeout5(timer);
|
|
37794
37794
|
this.process = null;
|
|
37795
|
-
|
|
37795
|
+
resolve14();
|
|
37796
37796
|
});
|
|
37797
37797
|
} else {
|
|
37798
37798
|
clearTimeout5(timer);
|
|
37799
|
-
|
|
37799
|
+
resolve14();
|
|
37800
37800
|
}
|
|
37801
37801
|
});
|
|
37802
37802
|
this.commandInProgress = false;
|
|
@@ -38041,11 +38041,11 @@ var init_server_manager = __esm({
|
|
|
38041
38041
|
async warmUpLanguageServer() {
|
|
38042
38042
|
try {
|
|
38043
38043
|
const { packageRootDir: packageRootDir2 } = await Promise.resolve().then(() => (init_package_paths(), package_paths_exports));
|
|
38044
|
-
const { resolve:
|
|
38044
|
+
const { resolve: resolve14 } = await import("path");
|
|
38045
38045
|
const config2 = {
|
|
38046
38046
|
checkErrors: "ON_CHANGE",
|
|
38047
38047
|
loglevel: "WARN",
|
|
38048
|
-
searchPath:
|
|
38048
|
+
searchPath: resolve14(packageRootDir2, "ql")
|
|
38049
38049
|
};
|
|
38050
38050
|
logger.info("Warming up language server (background JVM start)...");
|
|
38051
38051
|
await this.getLanguageServer(config2);
|
|
@@ -40527,8 +40527,8 @@ var require_adm_zip = __commonJS({
|
|
|
40527
40527
|
return null;
|
|
40528
40528
|
}
|
|
40529
40529
|
function fixPath(zipPath) {
|
|
40530
|
-
const { join:
|
|
40531
|
-
return
|
|
40530
|
+
const { join: join19, normalize, sep: sep2 } = pth.posix;
|
|
40531
|
+
return join19(".", normalize(sep2 + zipPath.split("\\").join(sep2) + sep2));
|
|
40532
40532
|
}
|
|
40533
40533
|
function filenameFilter(filterfn) {
|
|
40534
40534
|
if (filterfn instanceof RegExp) {
|
|
@@ -40923,10 +40923,10 @@ var require_adm_zip = __commonJS({
|
|
|
40923
40923
|
* @param {function|string} [props.namefix] - optional function to help fix filename
|
|
40924
40924
|
*/
|
|
40925
40925
|
addLocalFolderPromise: function(localPath2, props) {
|
|
40926
|
-
return new Promise((
|
|
40926
|
+
return new Promise((resolve14, reject) => {
|
|
40927
40927
|
this.addLocalFolderAsync2(Object.assign({ localPath: localPath2 }, props), (err, done) => {
|
|
40928
40928
|
if (err) reject(err);
|
|
40929
|
-
if (done)
|
|
40929
|
+
if (done) resolve14(this);
|
|
40930
40930
|
});
|
|
40931
40931
|
});
|
|
40932
40932
|
},
|
|
@@ -41113,12 +41113,12 @@ var require_adm_zip = __commonJS({
|
|
|
41113
41113
|
keepOriginalPermission = get_Bool(false, keepOriginalPermission);
|
|
41114
41114
|
overwrite = get_Bool(false, overwrite);
|
|
41115
41115
|
if (!callback) {
|
|
41116
|
-
return new Promise((
|
|
41116
|
+
return new Promise((resolve14, reject) => {
|
|
41117
41117
|
this.extractAllToAsync(targetPath, overwrite, keepOriginalPermission, function(err) {
|
|
41118
41118
|
if (err) {
|
|
41119
41119
|
reject(err);
|
|
41120
41120
|
} else {
|
|
41121
|
-
|
|
41121
|
+
resolve14(this);
|
|
41122
41122
|
}
|
|
41123
41123
|
});
|
|
41124
41124
|
});
|
|
@@ -41216,11 +41216,11 @@ var require_adm_zip = __commonJS({
|
|
|
41216
41216
|
*/
|
|
41217
41217
|
writeZipPromise: function(targetFileName, props) {
|
|
41218
41218
|
const { overwrite, perm } = Object.assign({ overwrite: true }, props);
|
|
41219
|
-
return new Promise((
|
|
41219
|
+
return new Promise((resolve14, reject) => {
|
|
41220
41220
|
if (!targetFileName && opts.filename) targetFileName = opts.filename;
|
|
41221
41221
|
if (!targetFileName) reject("ADM-ZIP: ZIP File Name Missing");
|
|
41222
41222
|
this.toBufferPromise().then((zipData) => {
|
|
41223
|
-
const ret = (done) => done ?
|
|
41223
|
+
const ret = (done) => done ? resolve14(done) : reject("ADM-ZIP: Wasn't able to write zip file");
|
|
41224
41224
|
filetools.writeFileToAsync(targetFileName, zipData, overwrite, perm, ret);
|
|
41225
41225
|
}, reject);
|
|
41226
41226
|
});
|
|
@@ -41229,8 +41229,8 @@ var require_adm_zip = __commonJS({
|
|
|
41229
41229
|
* @returns {Promise<Buffer>} A promise to the Buffer.
|
|
41230
41230
|
*/
|
|
41231
41231
|
toBufferPromise: function() {
|
|
41232
|
-
return new Promise((
|
|
41233
|
-
_zip.toAsyncBuffer(
|
|
41232
|
+
return new Promise((resolve14, reject) => {
|
|
41233
|
+
_zip.toAsyncBuffer(resolve14, reject);
|
|
41234
41234
|
});
|
|
41235
41235
|
},
|
|
41236
41236
|
/**
|
|
@@ -53328,7 +53328,7 @@ var Protocol = class {
|
|
|
53328
53328
|
return;
|
|
53329
53329
|
}
|
|
53330
53330
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
53331
|
-
await new Promise((
|
|
53331
|
+
await new Promise((resolve14) => setTimeout(resolve14, pollInterval));
|
|
53332
53332
|
options?.signal?.throwIfAborted();
|
|
53333
53333
|
}
|
|
53334
53334
|
} catch (error2) {
|
|
@@ -53345,7 +53345,7 @@ var Protocol = class {
|
|
|
53345
53345
|
*/
|
|
53346
53346
|
request(request, resultSchema, options) {
|
|
53347
53347
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
53348
|
-
return new Promise((
|
|
53348
|
+
return new Promise((resolve14, reject) => {
|
|
53349
53349
|
const earlyReject = (error2) => {
|
|
53350
53350
|
reject(error2);
|
|
53351
53351
|
};
|
|
@@ -53423,7 +53423,7 @@ var Protocol = class {
|
|
|
53423
53423
|
if (!parseResult.success) {
|
|
53424
53424
|
reject(parseResult.error);
|
|
53425
53425
|
} else {
|
|
53426
|
-
|
|
53426
|
+
resolve14(parseResult.data);
|
|
53427
53427
|
}
|
|
53428
53428
|
} catch (error2) {
|
|
53429
53429
|
reject(error2);
|
|
@@ -53684,12 +53684,12 @@ var Protocol = class {
|
|
|
53684
53684
|
}
|
|
53685
53685
|
} catch {
|
|
53686
53686
|
}
|
|
53687
|
-
return new Promise((
|
|
53687
|
+
return new Promise((resolve14, reject) => {
|
|
53688
53688
|
if (signal.aborted) {
|
|
53689
53689
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
53690
53690
|
return;
|
|
53691
53691
|
}
|
|
53692
|
-
const timeoutId = setTimeout(
|
|
53692
|
+
const timeoutId = setTimeout(resolve14, interval);
|
|
53693
53693
|
signal.addEventListener("abort", () => {
|
|
53694
53694
|
clearTimeout(timeoutId);
|
|
53695
53695
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -54789,7 +54789,7 @@ var McpServer = class {
|
|
|
54789
54789
|
let task = createTaskResult.task;
|
|
54790
54790
|
const pollInterval = task.pollInterval ?? 5e3;
|
|
54791
54791
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
54792
|
-
await new Promise((
|
|
54792
|
+
await new Promise((resolve14) => setTimeout(resolve14, pollInterval));
|
|
54793
54793
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
54794
54794
|
if (!updatedTask) {
|
|
54795
54795
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -55432,12 +55432,12 @@ var StdioServerTransport = class {
|
|
|
55432
55432
|
this.onclose?.();
|
|
55433
55433
|
}
|
|
55434
55434
|
send(message) {
|
|
55435
|
-
return new Promise((
|
|
55435
|
+
return new Promise((resolve14) => {
|
|
55436
55436
|
const json2 = serializeMessage(message);
|
|
55437
55437
|
if (this._stdout.write(json2)) {
|
|
55438
|
-
|
|
55438
|
+
resolve14();
|
|
55439
55439
|
} else {
|
|
55440
|
-
this._stdout.once("drain",
|
|
55440
|
+
this._stdout.once("drain", resolve14);
|
|
55441
55441
|
}
|
|
55442
55442
|
});
|
|
55443
55443
|
}
|
|
@@ -55870,7 +55870,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
|
|
55870
55870
|
});
|
|
55871
55871
|
if (!chunk) {
|
|
55872
55872
|
if (i === 1) {
|
|
55873
|
-
await new Promise((
|
|
55873
|
+
await new Promise((resolve14) => setTimeout(resolve14));
|
|
55874
55874
|
maxReadCount = 3;
|
|
55875
55875
|
continue;
|
|
55876
55876
|
}
|
|
@@ -56366,9 +56366,9 @@ data:
|
|
|
56366
56366
|
const initRequest = messages.find((m) => isInitializeRequest(m));
|
|
56367
56367
|
const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
|
|
56368
56368
|
if (this._enableJsonResponse) {
|
|
56369
|
-
return new Promise((
|
|
56369
|
+
return new Promise((resolve14) => {
|
|
56370
56370
|
this._streamMapping.set(streamId, {
|
|
56371
|
-
resolveJson:
|
|
56371
|
+
resolveJson: resolve14,
|
|
56372
56372
|
cleanup: () => {
|
|
56373
56373
|
this._streamMapping.delete(streamId);
|
|
56374
56374
|
}
|
|
@@ -56702,8 +56702,8 @@ var StreamableHTTPServerTransport = class {
|
|
|
56702
56702
|
var import_express = __toESM(require_express2(), 1);
|
|
56703
56703
|
var import_cors = __toESM(require_lib3(), 1);
|
|
56704
56704
|
var import_dotenv = __toESM(require_main(), 1);
|
|
56705
|
-
import { realpathSync } from "fs";
|
|
56706
|
-
import { resolve as
|
|
56705
|
+
import { realpathSync as realpathSync2 } from "fs";
|
|
56706
|
+
import { resolve as resolve13 } from "path";
|
|
56707
56707
|
import { pathToFileURL as pathToFileURL5 } from "url";
|
|
56708
56708
|
|
|
56709
56709
|
// src/lib/cli-tool-registry.ts
|
|
@@ -57005,8 +57005,41 @@ function getOrCreateLogDirectory(logDir) {
|
|
|
57005
57005
|
// src/lib/cli-tool-registry.ts
|
|
57006
57006
|
init_package_paths();
|
|
57007
57007
|
init_temp_dir();
|
|
57008
|
-
import { writeFileSync as writeFileSync2, rmSync, existsSync as existsSync4, mkdirSync as mkdirSync5 } from "fs";
|
|
57008
|
+
import { writeFileSync as writeFileSync2, rmSync, existsSync as existsSync4, mkdirSync as mkdirSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
57009
57009
|
import { basename as basename2, dirname as dirname4, isAbsolute as isAbsolute4, join as join6, resolve as resolve4 } from "path";
|
|
57010
|
+
function resolveDatabasePath(dbPath) {
|
|
57011
|
+
if (existsSync4(join6(dbPath, "codeql-database.yml"))) {
|
|
57012
|
+
return dbPath;
|
|
57013
|
+
}
|
|
57014
|
+
try {
|
|
57015
|
+
const entries = readdirSync2(dbPath);
|
|
57016
|
+
const candidates = [];
|
|
57017
|
+
for (const entry of entries) {
|
|
57018
|
+
const candidate = join6(dbPath, entry);
|
|
57019
|
+
try {
|
|
57020
|
+
if (statSync2(candidate).isDirectory() && existsSync4(join6(candidate, "codeql-database.yml"))) {
|
|
57021
|
+
candidates.push(candidate);
|
|
57022
|
+
}
|
|
57023
|
+
} catch {
|
|
57024
|
+
}
|
|
57025
|
+
}
|
|
57026
|
+
if (candidates.length === 1) {
|
|
57027
|
+
logger.info(`Resolved database directory: ${dbPath} -> ${candidates[0]}`);
|
|
57028
|
+
return candidates[0];
|
|
57029
|
+
}
|
|
57030
|
+
if (candidates.length > 1) {
|
|
57031
|
+
const names = candidates.map((c) => basename2(c)).join(", ");
|
|
57032
|
+
throw new Error(
|
|
57033
|
+
`Ambiguous database path: ${dbPath} contains multiple databases (${names}). Specify the full path to the desired database subfolder.`
|
|
57034
|
+
);
|
|
57035
|
+
}
|
|
57036
|
+
} catch (err) {
|
|
57037
|
+
if (err instanceof Error && err.message.startsWith("Ambiguous database path")) {
|
|
57038
|
+
throw err;
|
|
57039
|
+
}
|
|
57040
|
+
}
|
|
57041
|
+
return dbPath;
|
|
57042
|
+
}
|
|
57010
57043
|
var defaultCLIResultProcessor = (result, _params) => {
|
|
57011
57044
|
if (!result.success) {
|
|
57012
57045
|
return `Command failed (exit code ${result.exitCode || "unknown"}):
|
|
@@ -57044,7 +57077,7 @@ function registerCLITool(server, definition) {
|
|
|
57044
57077
|
const tempDirsToCleanup = [];
|
|
57045
57078
|
try {
|
|
57046
57079
|
logger.info(`Executing CLI tool: ${name}`, { command, subcommand, params });
|
|
57047
|
-
const formatShouldBePassedToCLI = name === "codeql_bqrs_interpret" || name === "codeql_bqrs_decode" || name === "codeql_bqrs_info" || name === "codeql_generate_query-help" || name === "codeql_database_analyze";
|
|
57080
|
+
const formatShouldBePassedToCLI = name === "codeql_bqrs_interpret" || name === "codeql_bqrs_decode" || name === "codeql_bqrs_info" || name === "codeql_generate_query-help" || name === "codeql_database_analyze" || name === "codeql_resolve_files";
|
|
57048
57081
|
const extractedParams = formatShouldBePassedToCLI ? {
|
|
57049
57082
|
_positional: params._positional || [],
|
|
57050
57083
|
files: params.files,
|
|
@@ -57122,7 +57155,7 @@ function registerCLITool(server, definition) {
|
|
|
57122
57155
|
positionalArgs = [...positionalArgs, qlref];
|
|
57123
57156
|
}
|
|
57124
57157
|
if (options.database && name === "codeql_resolve_database") {
|
|
57125
|
-
positionalArgs = [...positionalArgs, options.database];
|
|
57158
|
+
positionalArgs = [...positionalArgs, resolveDatabasePath(options.database)];
|
|
57126
57159
|
delete options.database;
|
|
57127
57160
|
}
|
|
57128
57161
|
if (options.database && name === "codeql_database_create") {
|
|
@@ -57131,7 +57164,7 @@ function registerCLITool(server, definition) {
|
|
|
57131
57164
|
}
|
|
57132
57165
|
if (name === "codeql_database_analyze") {
|
|
57133
57166
|
if (options.database) {
|
|
57134
|
-
positionalArgs = [...positionalArgs, options.database];
|
|
57167
|
+
positionalArgs = [...positionalArgs, resolveDatabasePath(options.database)];
|
|
57135
57168
|
delete options.database;
|
|
57136
57169
|
}
|
|
57137
57170
|
if (options.queries) {
|
|
@@ -57162,6 +57195,9 @@ function registerCLITool(server, definition) {
|
|
|
57162
57195
|
options.database = resolve4(getUserWorkspaceDir(), options.database);
|
|
57163
57196
|
logger.info(`Resolved database path to: ${options.database}`);
|
|
57164
57197
|
}
|
|
57198
|
+
if (options.database && typeof options.database === "string") {
|
|
57199
|
+
options.database = resolveDatabasePath(options.database);
|
|
57200
|
+
}
|
|
57165
57201
|
const resolvedQuery = await resolveQueryPath(params, logger);
|
|
57166
57202
|
if (resolvedQuery) {
|
|
57167
57203
|
positionalArgs = [...positionalArgs, resolvedQuery];
|
|
@@ -57241,6 +57277,11 @@ function registerCLITool(server, definition) {
|
|
|
57241
57277
|
positionalArgs = [...positionalArgs, directory];
|
|
57242
57278
|
}
|
|
57243
57279
|
break;
|
|
57280
|
+
case "codeql_resolve_files":
|
|
57281
|
+
if (dir) {
|
|
57282
|
+
positionalArgs = [...positionalArgs, dir];
|
|
57283
|
+
}
|
|
57284
|
+
break;
|
|
57244
57285
|
default:
|
|
57245
57286
|
break;
|
|
57246
57287
|
}
|
|
@@ -60714,6 +60755,18 @@ async function findCodeQLQueryFiles(queryFilePath, language, resolveMetadata = t
|
|
|
60714
60755
|
}
|
|
60715
60756
|
const testPackPath = findNearestQlpack(testDir);
|
|
60716
60757
|
const testPackDir = testPackPath ? path.dirname(testPackPath) : testDir;
|
|
60758
|
+
const hints = [];
|
|
60759
|
+
if (!testDirectory.exists) {
|
|
60760
|
+
hints.push("No test directory found. To run this query you will need a user-provided database (databasePath). Test-driven profiling is not available without tests.");
|
|
60761
|
+
} else if (testCodePaths.length === 0) {
|
|
60762
|
+
hints.push("Test directory exists but contains no test source code files. Consider creating test code to enable test-driven workflows.");
|
|
60763
|
+
}
|
|
60764
|
+
if (!expectedResultsPath.exists && testDirectory.exists) {
|
|
60765
|
+
hints.push("No .expected file found. Run codeql_test_run to generate initial expected results, then verify them.");
|
|
60766
|
+
}
|
|
60767
|
+
if (!documentationPath.exists) {
|
|
60768
|
+
hints.push("No query documentation (.md) file found. Use the document_codeql_query prompt to generate one.");
|
|
60769
|
+
}
|
|
60717
60770
|
return {
|
|
60718
60771
|
queryName,
|
|
60719
60772
|
language: detectedLanguage,
|
|
@@ -60736,6 +60789,7 @@ async function findCodeQLQueryFiles(queryFilePath, language, resolveMetadata = t
|
|
|
60736
60789
|
testDatabaseDir: testDatabasePath.path
|
|
60737
60790
|
}
|
|
60738
60791
|
},
|
|
60792
|
+
hints,
|
|
60739
60793
|
metadata,
|
|
60740
60794
|
missingFiles,
|
|
60741
60795
|
packMetadata,
|
|
@@ -60837,15 +60891,16 @@ var codeqlGenerateQueryHelpTool = {
|
|
|
60837
60891
|
};
|
|
60838
60892
|
|
|
60839
60893
|
// src/tools/codeql/list-databases.ts
|
|
60840
|
-
import { existsSync as existsSync6, readdirSync as
|
|
60894
|
+
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
|
|
60841
60895
|
import { join as join8 } from "path";
|
|
60842
60896
|
|
|
60843
60897
|
// src/lib/discovery-config.ts
|
|
60898
|
+
import { delimiter as delimiter5 } from "path";
|
|
60844
60899
|
function parsePathList(envValue) {
|
|
60845
60900
|
if (!envValue) {
|
|
60846
60901
|
return [];
|
|
60847
60902
|
}
|
|
60848
|
-
return envValue.split(
|
|
60903
|
+
return envValue.split(delimiter5).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
60849
60904
|
}
|
|
60850
60905
|
function getDatabaseBaseDirs() {
|
|
60851
60906
|
return parsePathList(process.env.CODEQL_DATABASES_BASE_DIRS);
|
|
@@ -60894,14 +60949,14 @@ async function discoverDatabases(baseDirs, language) {
|
|
|
60894
60949
|
}
|
|
60895
60950
|
let entries;
|
|
60896
60951
|
try {
|
|
60897
|
-
entries =
|
|
60952
|
+
entries = readdirSync4(baseDir);
|
|
60898
60953
|
} catch {
|
|
60899
60954
|
continue;
|
|
60900
60955
|
}
|
|
60901
60956
|
for (const entry of entries) {
|
|
60902
60957
|
const entryPath = join8(baseDir, entry);
|
|
60903
60958
|
try {
|
|
60904
|
-
if (!
|
|
60959
|
+
if (!statSync4(entryPath).isDirectory()) {
|
|
60905
60960
|
continue;
|
|
60906
60961
|
}
|
|
60907
60962
|
} catch {
|
|
@@ -60990,7 +61045,7 @@ function registerListDatabasesTool(server) {
|
|
|
60990
61045
|
}
|
|
60991
61046
|
|
|
60992
61047
|
// src/tools/codeql/list-mrva-run-results.ts
|
|
60993
|
-
import { existsSync as existsSync7, readdirSync as
|
|
61048
|
+
import { existsSync as existsSync7, readdirSync as readdirSync5, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
|
|
60994
61049
|
import { join as join9 } from "path";
|
|
60995
61050
|
init_logger();
|
|
60996
61051
|
var NUMERIC_DIR_PATTERN = /^\d+$/;
|
|
@@ -61003,14 +61058,14 @@ async function discoverMrvaRunResults(resultsDirs, runId) {
|
|
|
61003
61058
|
}
|
|
61004
61059
|
let entries;
|
|
61005
61060
|
try {
|
|
61006
|
-
entries =
|
|
61061
|
+
entries = readdirSync5(dir);
|
|
61007
61062
|
} catch {
|
|
61008
61063
|
continue;
|
|
61009
61064
|
}
|
|
61010
61065
|
for (const entry of entries) {
|
|
61011
61066
|
const entryPath = join9(dir, entry);
|
|
61012
61067
|
try {
|
|
61013
|
-
if (!
|
|
61068
|
+
if (!statSync5(entryPath).isDirectory()) {
|
|
61014
61069
|
continue;
|
|
61015
61070
|
}
|
|
61016
61071
|
} catch {
|
|
@@ -61045,7 +61100,7 @@ function discoverRepoResults(runPath) {
|
|
|
61045
61100
|
const repos = [];
|
|
61046
61101
|
let ownerEntries;
|
|
61047
61102
|
try {
|
|
61048
|
-
ownerEntries =
|
|
61103
|
+
ownerEntries = readdirSync5(runPath);
|
|
61049
61104
|
} catch {
|
|
61050
61105
|
return repos;
|
|
61051
61106
|
}
|
|
@@ -61055,7 +61110,7 @@ function discoverRepoResults(runPath) {
|
|
|
61055
61110
|
}
|
|
61056
61111
|
const ownerPath = join9(runPath, ownerEntry);
|
|
61057
61112
|
try {
|
|
61058
|
-
if (!
|
|
61113
|
+
if (!statSync5(ownerPath).isDirectory()) {
|
|
61059
61114
|
continue;
|
|
61060
61115
|
}
|
|
61061
61116
|
} catch {
|
|
@@ -61063,14 +61118,14 @@ function discoverRepoResults(runPath) {
|
|
|
61063
61118
|
}
|
|
61064
61119
|
let repoEntries;
|
|
61065
61120
|
try {
|
|
61066
|
-
repoEntries =
|
|
61121
|
+
repoEntries = readdirSync5(ownerPath);
|
|
61067
61122
|
} catch {
|
|
61068
61123
|
continue;
|
|
61069
61124
|
}
|
|
61070
61125
|
for (const repoEntry of repoEntries) {
|
|
61071
61126
|
const repoPath = join9(ownerPath, repoEntry);
|
|
61072
61127
|
try {
|
|
61073
|
-
if (!
|
|
61128
|
+
if (!statSync5(repoPath).isDirectory()) {
|
|
61074
61129
|
continue;
|
|
61075
61130
|
}
|
|
61076
61131
|
} catch {
|
|
@@ -61177,7 +61232,7 @@ function registerListMrvaRunResultsTool(server) {
|
|
|
61177
61232
|
}
|
|
61178
61233
|
|
|
61179
61234
|
// src/tools/codeql/list-query-run-results.ts
|
|
61180
|
-
import { existsSync as existsSync8, readdirSync as
|
|
61235
|
+
import { existsSync as existsSync8, readdirSync as readdirSync6, readFileSync as readFileSync7, statSync as statSync6 } from "fs";
|
|
61181
61236
|
import { join as join10 } from "path";
|
|
61182
61237
|
init_logger();
|
|
61183
61238
|
var QUERY_RUN_DIR_PATTERN = /^(.+\.ql)-(.+)$/;
|
|
@@ -61219,14 +61274,14 @@ async function discoverQueryRunResults(resultsDirs, filter) {
|
|
|
61219
61274
|
}
|
|
61220
61275
|
let entries;
|
|
61221
61276
|
try {
|
|
61222
|
-
entries =
|
|
61277
|
+
entries = readdirSync6(dir);
|
|
61223
61278
|
} catch {
|
|
61224
61279
|
continue;
|
|
61225
61280
|
}
|
|
61226
61281
|
for (const entry of entries) {
|
|
61227
61282
|
const entryPath = join10(dir, entry);
|
|
61228
61283
|
try {
|
|
61229
|
-
if (!
|
|
61284
|
+
if (!statSync6(entryPath).isDirectory()) {
|
|
61230
61285
|
continue;
|
|
61231
61286
|
}
|
|
61232
61287
|
} catch {
|
|
@@ -61434,57 +61489,87 @@ import { basename as basename4, dirname as dirname6, join as join11 } from "path
|
|
|
61434
61489
|
|
|
61435
61490
|
// src/lib/evaluator-log-parser.ts
|
|
61436
61491
|
init_logger();
|
|
61437
|
-
import {
|
|
61492
|
+
import { createReadStream } from "fs";
|
|
61493
|
+
import { createInterface } from "readline";
|
|
61438
61494
|
function detectLogFormat(firstEvent) {
|
|
61439
61495
|
if (typeof firstEvent.type === "string") {
|
|
61440
61496
|
return "raw";
|
|
61441
61497
|
}
|
|
61442
61498
|
return "summary";
|
|
61443
61499
|
}
|
|
61444
|
-
function
|
|
61445
|
-
const
|
|
61446
|
-
|
|
61447
|
-
|
|
61448
|
-
}
|
|
61449
|
-
const parts = trimmed.split(/\n\}\s*\n\s*\{/);
|
|
61450
|
-
if (parts.length === 1) {
|
|
61451
|
-
return [trimmed];
|
|
61452
|
-
}
|
|
61453
|
-
return parts.map((part, idx) => {
|
|
61454
|
-
if (idx === 0) {
|
|
61455
|
-
return part + "\n}";
|
|
61456
|
-
}
|
|
61457
|
-
if (idx === parts.length - 1) {
|
|
61458
|
-
return "{\n" + part;
|
|
61459
|
-
}
|
|
61460
|
-
return "{\n" + part + "\n}";
|
|
61500
|
+
async function* streamJsonObjects(logPath) {
|
|
61501
|
+
const rl = createInterface({
|
|
61502
|
+
input: createReadStream(logPath, { encoding: "utf-8" }),
|
|
61503
|
+
crlfDelay: Infinity
|
|
61461
61504
|
});
|
|
61462
|
-
|
|
61463
|
-
|
|
61464
|
-
|
|
61465
|
-
const
|
|
61466
|
-
const
|
|
61467
|
-
|
|
61468
|
-
|
|
61469
|
-
|
|
61470
|
-
|
|
61471
|
-
|
|
61472
|
-
|
|
61473
|
-
|
|
61505
|
+
let depth = 0;
|
|
61506
|
+
let inString = false;
|
|
61507
|
+
let escape2 = false;
|
|
61508
|
+
const lines = [];
|
|
61509
|
+
for await (const line of rl) {
|
|
61510
|
+
for (const ch of line) {
|
|
61511
|
+
if (escape2) {
|
|
61512
|
+
escape2 = false;
|
|
61513
|
+
continue;
|
|
61514
|
+
}
|
|
61515
|
+
if (ch === "\\" && inString) {
|
|
61516
|
+
escape2 = true;
|
|
61517
|
+
continue;
|
|
61518
|
+
}
|
|
61519
|
+
if (ch === '"') {
|
|
61520
|
+
inString = !inString;
|
|
61521
|
+
continue;
|
|
61522
|
+
}
|
|
61523
|
+
if (inString) continue;
|
|
61524
|
+
if (ch === "{") depth++;
|
|
61525
|
+
if (ch === "}") depth--;
|
|
61526
|
+
}
|
|
61527
|
+
if (depth > 0 || depth === 0 && line.trim().length > 0 && lines.length > 0) {
|
|
61528
|
+
lines.push(line);
|
|
61529
|
+
} else if (depth === 0 && lines.length === 0 && line.trim().length > 0) {
|
|
61530
|
+
lines.push(line);
|
|
61531
|
+
}
|
|
61532
|
+
if (depth === 0 && lines.length > 0) {
|
|
61533
|
+
const objStr = lines.join("\n");
|
|
61534
|
+
lines.length = 0;
|
|
61535
|
+
inString = false;
|
|
61536
|
+
escape2 = false;
|
|
61537
|
+
if (objStr.trim().length === 0) continue;
|
|
61538
|
+
try {
|
|
61539
|
+
yield JSON.parse(objStr);
|
|
61540
|
+
} catch {
|
|
61541
|
+
logger.warn(
|
|
61542
|
+
`Failed to parse evaluator log object: ${objStr.substring(0, 120)}...`
|
|
61543
|
+
);
|
|
61544
|
+
}
|
|
61545
|
+
}
|
|
61546
|
+
}
|
|
61547
|
+
if (lines.length > 0) {
|
|
61548
|
+
const objStr = lines.join("\n");
|
|
61549
|
+
if (objStr.trim().length > 0) {
|
|
61550
|
+
try {
|
|
61551
|
+
yield JSON.parse(objStr);
|
|
61552
|
+
} catch {
|
|
61553
|
+
logger.warn(
|
|
61554
|
+
`Failed to parse trailing evaluator log object: ${objStr.substring(0, 120)}...`
|
|
61555
|
+
);
|
|
61556
|
+
}
|
|
61474
61557
|
}
|
|
61475
61558
|
}
|
|
61476
|
-
return results;
|
|
61477
61559
|
}
|
|
61478
|
-
function
|
|
61479
|
-
const events = parseJsonObjects(logPath);
|
|
61560
|
+
async function processRawEvents(events) {
|
|
61480
61561
|
let codeqlVersion;
|
|
61481
61562
|
const queryStartEvents = /* @__PURE__ */ new Map();
|
|
61482
61563
|
const predicateStartEvents = /* @__PURE__ */ new Map();
|
|
61564
|
+
const pipelineStartNanoTimes = /* @__PURE__ */ new Map();
|
|
61565
|
+
const pipelineToPredicateMap = /* @__PURE__ */ new Map();
|
|
61483
61566
|
const queryPredicates = /* @__PURE__ */ new Map();
|
|
61484
61567
|
const queryEndNanoTimes = /* @__PURE__ */ new Map();
|
|
61485
61568
|
const queryCacheHits = /* @__PURE__ */ new Map();
|
|
61486
61569
|
let firstQueryEventId;
|
|
61487
|
-
|
|
61570
|
+
let totalEvents = 0;
|
|
61571
|
+
for await (const event of events) {
|
|
61572
|
+
totalEvents++;
|
|
61488
61573
|
const eventType = event.type;
|
|
61489
61574
|
switch (eventType) {
|
|
61490
61575
|
case "LOG_HEADER": {
|
|
@@ -61513,6 +61598,11 @@ function parseRawEvaluatorLog(logPath) {
|
|
|
61513
61598
|
case "PREDICATE_STARTED": {
|
|
61514
61599
|
const eid = event.eventId;
|
|
61515
61600
|
const deps = event.dependencies;
|
|
61601
|
+
const raObj = event.ra;
|
|
61602
|
+
let raSteps;
|
|
61603
|
+
if (raObj && Array.isArray(raObj.pipeline)) {
|
|
61604
|
+
raSteps = raObj.pipeline.map((s) => s.trim());
|
|
61605
|
+
}
|
|
61516
61606
|
predicateStartEvents.set(eid, {
|
|
61517
61607
|
predicateName: event.predicateName || "unknown",
|
|
61518
61608
|
position: event.position,
|
|
@@ -61520,20 +61610,34 @@ function parseRawEvaluatorLog(logPath) {
|
|
|
61520
61610
|
dependencies: deps ? Object.keys(deps) : [],
|
|
61521
61611
|
queryCausingWork: event.queryCausingWork,
|
|
61522
61612
|
nanoTime: event.nanoTime,
|
|
61523
|
-
pipelineCount: 0
|
|
61613
|
+
pipelineCount: 0,
|
|
61614
|
+
raSteps,
|
|
61615
|
+
pipelineStages: []
|
|
61524
61616
|
});
|
|
61525
61617
|
break;
|
|
61526
61618
|
}
|
|
61619
|
+
case "PIPELINE_STARTED": {
|
|
61620
|
+
const eid = event.eventId;
|
|
61621
|
+
pipelineStartNanoTimes.set(eid, event.nanoTime);
|
|
61622
|
+
const predEid = event.predicateStartEvent;
|
|
61623
|
+
pipelineToPredicateMap.set(eid, predEid);
|
|
61624
|
+
break;
|
|
61625
|
+
}
|
|
61527
61626
|
case "PIPELINE_COMPLETED": {
|
|
61528
61627
|
const pipelineStartEid = event.startEvent;
|
|
61529
|
-
const
|
|
61530
|
-
|
|
61531
|
-
)
|
|
61532
|
-
if (pipelineStartEvt) {
|
|
61533
|
-
const predEid = pipelineStartEvt.predicateStartEvent;
|
|
61628
|
+
const predEid = pipelineToPredicateMap.get(pipelineStartEid);
|
|
61629
|
+
const startNano = pipelineStartNanoTimes.get(pipelineStartEid);
|
|
61630
|
+
if (predEid !== void 0) {
|
|
61534
61631
|
const predStart = predicateStartEvents.get(predEid);
|
|
61535
61632
|
if (predStart) {
|
|
61536
61633
|
predStart.pipelineCount += 1;
|
|
61634
|
+
const pipelineDurationMs = startNano !== void 0 ? (event.nanoTime - startNano) / 1e6 : 0;
|
|
61635
|
+
predStart.pipelineStages.push({
|
|
61636
|
+
durationMs: pipelineDurationMs,
|
|
61637
|
+
resultSize: event.resultSize ?? 0,
|
|
61638
|
+
counts: event.counts ?? [],
|
|
61639
|
+
duplicationPercentages: event.duplicationPercentages
|
|
61640
|
+
});
|
|
61537
61641
|
}
|
|
61538
61642
|
}
|
|
61539
61643
|
break;
|
|
@@ -61551,7 +61655,9 @@ function parseRawEvaluatorLog(logPath) {
|
|
|
61551
61655
|
resultSize: event.resultSize,
|
|
61552
61656
|
pipelineCount: predStart.pipelineCount > 0 ? predStart.pipelineCount : void 0,
|
|
61553
61657
|
evaluationStrategy: predStart.predicateType,
|
|
61554
|
-
dependencies: predStart.dependencies
|
|
61658
|
+
dependencies: predStart.dependencies,
|
|
61659
|
+
raSteps: predStart.raSteps,
|
|
61660
|
+
pipelineStages: predStart.pipelineStages.length > 0 ? predStart.pipelineStages : void 0
|
|
61555
61661
|
};
|
|
61556
61662
|
const qEid = predStart.queryCausingWork ?? firstQueryEventId;
|
|
61557
61663
|
if (qEid !== void 0) {
|
|
@@ -61591,16 +61697,17 @@ function parseRawEvaluatorLog(logPath) {
|
|
|
61591
61697
|
codeqlVersion,
|
|
61592
61698
|
logFormat: "raw",
|
|
61593
61699
|
queries,
|
|
61594
|
-
totalEvents
|
|
61700
|
+
totalEvents
|
|
61595
61701
|
};
|
|
61596
61702
|
}
|
|
61597
|
-
function
|
|
61598
|
-
const events = parseJsonObjects(logPath);
|
|
61703
|
+
async function processSummaryEvents(events) {
|
|
61599
61704
|
let codeqlVersion;
|
|
61600
61705
|
const queryPredicatesMap = /* @__PURE__ */ new Map();
|
|
61601
61706
|
const queryTotalMs = /* @__PURE__ */ new Map();
|
|
61602
61707
|
const queryCacheHits = /* @__PURE__ */ new Map();
|
|
61603
|
-
|
|
61708
|
+
let totalEvents = 0;
|
|
61709
|
+
for await (const event of events) {
|
|
61710
|
+
totalEvents++;
|
|
61604
61711
|
if (event.summaryLogVersion !== void 0) {
|
|
61605
61712
|
codeqlVersion = event.codeqlVersion;
|
|
61606
61713
|
continue;
|
|
@@ -61617,6 +61724,11 @@ function parseSummaryLog(logPath) {
|
|
|
61617
61724
|
const queryName = event.queryCausingWork || "unknown";
|
|
61618
61725
|
const deps = event.dependencies;
|
|
61619
61726
|
const pipelineRuns = event.pipelineRuns;
|
|
61727
|
+
const raObj = event.ra;
|
|
61728
|
+
let raSteps;
|
|
61729
|
+
if (typeof raObj === "string" && raObj.length > 0) {
|
|
61730
|
+
raSteps = raObj.replace(/\r\n/g, "\n").split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
61731
|
+
}
|
|
61620
61732
|
const profile = {
|
|
61621
61733
|
predicateName,
|
|
61622
61734
|
position: event.position,
|
|
@@ -61624,7 +61736,8 @@ function parseSummaryLog(logPath) {
|
|
|
61624
61736
|
resultSize: event.resultSize,
|
|
61625
61737
|
pipelineCount: pipelineRuns,
|
|
61626
61738
|
evaluationStrategy: strategy,
|
|
61627
|
-
dependencies: deps ? Object.keys(deps) : []
|
|
61739
|
+
dependencies: deps ? Object.keys(deps) : [],
|
|
61740
|
+
raSteps
|
|
61628
61741
|
};
|
|
61629
61742
|
if (event.isCached === true || strategy === "CACHEHIT") {
|
|
61630
61743
|
queryCacheHits.set(
|
|
@@ -61657,143 +61770,142 @@ function parseSummaryLog(logPath) {
|
|
|
61657
61770
|
codeqlVersion,
|
|
61658
61771
|
logFormat: "summary",
|
|
61659
61772
|
queries,
|
|
61660
|
-
totalEvents
|
|
61773
|
+
totalEvents
|
|
61661
61774
|
};
|
|
61662
61775
|
}
|
|
61663
|
-
function parseEvaluatorLog(logPath) {
|
|
61664
|
-
const
|
|
61665
|
-
|
|
61776
|
+
async function parseEvaluatorLog(logPath) {
|
|
61777
|
+
const stream = streamJsonObjects(logPath);
|
|
61778
|
+
const iterator = stream[Symbol.asyncIterator]();
|
|
61779
|
+
const first = await iterator.next();
|
|
61780
|
+
if (first.done) {
|
|
61666
61781
|
return {
|
|
61667
61782
|
logFormat: "raw",
|
|
61668
61783
|
queries: [],
|
|
61669
61784
|
totalEvents: 0
|
|
61670
61785
|
};
|
|
61671
61786
|
}
|
|
61672
|
-
const
|
|
61787
|
+
const firstEvent = first.value;
|
|
61788
|
+
const format = detectLogFormat(firstEvent);
|
|
61789
|
+
async function* prependFirst() {
|
|
61790
|
+
yield firstEvent;
|
|
61791
|
+
for (; ; ) {
|
|
61792
|
+
const next = await iterator.next();
|
|
61793
|
+
if (next.done) break;
|
|
61794
|
+
yield next.value;
|
|
61795
|
+
}
|
|
61796
|
+
}
|
|
61673
61797
|
if (format === "raw") {
|
|
61674
|
-
return
|
|
61798
|
+
return processRawEvents(prependFirst());
|
|
61675
61799
|
}
|
|
61676
|
-
return
|
|
61800
|
+
return processSummaryEvents(prependFirst());
|
|
61677
61801
|
}
|
|
61678
61802
|
|
|
61679
61803
|
// src/tools/codeql/profile-codeql-query-from-logs.ts
|
|
61680
61804
|
init_logger();
|
|
61681
|
-
function
|
|
61682
|
-
return
|
|
61805
|
+
function getTopPredicates(predicates, topN) {
|
|
61806
|
+
return [...predicates].sort((a, b) => b.durationMs - a.durationMs).slice(0, topN);
|
|
61683
61807
|
}
|
|
61684
|
-
function
|
|
61808
|
+
function buildDetailFile(profile, topN) {
|
|
61685
61809
|
const lines = [];
|
|
61686
|
-
|
|
61687
|
-
lines.push("
|
|
61810
|
+
const lineIndex = /* @__PURE__ */ new Map();
|
|
61811
|
+
lines.push("# CodeQL Evaluator Profile \u2014 Predicate Detail");
|
|
61812
|
+
lines.push(`# Log format: ${profile.logFormat}`);
|
|
61813
|
+
if (profile.codeqlVersion) {
|
|
61814
|
+
lines.push(`# CodeQL version: ${profile.codeqlVersion}`);
|
|
61815
|
+
}
|
|
61816
|
+
lines.push(`# Use read_file with line ranges from the JSON response to access individual predicates.`);
|
|
61688
61817
|
lines.push("");
|
|
61689
|
-
|
|
61690
|
-
const query = profile.queries[
|
|
61691
|
-
|
|
61692
|
-
|
|
61693
|
-
|
|
61694
|
-
predicateCount: 0,
|
|
61695
|
-
cacheHits: 0
|
|
61696
|
-
};
|
|
61697
|
-
const qLabel = sanitizeMermaid(basename4(query.queryName));
|
|
61698
|
-
lines.push(
|
|
61699
|
-
` QUERY["${qLabel}<br/>Total: ${query.totalDurationMs.toFixed(2)}ms<br/>Predicates: ${query.predicateCount}"]`
|
|
61700
|
-
);
|
|
61818
|
+
for (let qIdx = 0; qIdx < profile.queries.length; qIdx++) {
|
|
61819
|
+
const query = profile.queries[qIdx];
|
|
61820
|
+
const qName = basename4(query.queryName);
|
|
61821
|
+
lines.push(`== Query: ${qName} ==`);
|
|
61822
|
+
lines.push(` Total: ${query.totalDurationMs.toFixed(2)}ms | Predicates evaluated: ${query.predicateCount} | Cache hits: ${query.cacheHits}`);
|
|
61701
61823
|
lines.push("");
|
|
61702
|
-
const
|
|
61703
|
-
|
|
61704
|
-
|
|
61705
|
-
const name = sanitizeMermaid(pred.predicateName).substring(0, 50);
|
|
61706
|
-
const dur = pred.durationMs.toFixed(2);
|
|
61707
|
-
const size = pred.resultSize !== void 0 ? String(pred.resultSize) : "?";
|
|
61708
|
-
lines.push(
|
|
61709
|
-
` ${nodeId}["${name}<br/>${dur}ms | ${size} results"]`
|
|
61710
|
-
);
|
|
61711
|
-
});
|
|
61712
|
-
lines.push("");
|
|
61713
|
-
topPredicates.forEach((_pred, idx) => {
|
|
61714
|
-
lines.push(` QUERY --> P${idx}`);
|
|
61824
|
+
const evalOrderMap = /* @__PURE__ */ new Map();
|
|
61825
|
+
query.predicates.forEach((pred, idx) => {
|
|
61826
|
+
evalOrderMap.set(pred, idx + 1);
|
|
61715
61827
|
});
|
|
61716
|
-
|
|
61717
|
-
|
|
61718
|
-
|
|
61719
|
-
|
|
61720
|
-
|
|
61721
|
-
|
|
61722
|
-
|
|
61723
|
-
|
|
61724
|
-
|
|
61725
|
-
|
|
61726
|
-
|
|
61727
|
-
|
|
61728
|
-
|
|
61729
|
-
|
|
61730
|
-
|
|
61731
|
-
|
|
61732
|
-
|
|
61733
|
-
|
|
61734
|
-
lines.push(
|
|
61735
|
-
|
|
61736
|
-
|
|
61737
|
-
|
|
61738
|
-
}
|
|
61828
|
+
const top = getTopPredicates(query.predicates, topN);
|
|
61829
|
+
for (const pred of top) {
|
|
61830
|
+
const startLine = lines.length + 1;
|
|
61831
|
+
lines.push(`--- ${pred.predicateName} ---`);
|
|
61832
|
+
lines.push(` Eval order: ${evalOrderMap.get(pred) ?? "?"} of ${query.predicateCount}`);
|
|
61833
|
+
lines.push(` Duration: ${pred.durationMs.toFixed(2)} ms`);
|
|
61834
|
+
lines.push(` Result: ${pred.resultSize ?? "?"} tuples`);
|
|
61835
|
+
lines.push(` Strategy: ${pred.evaluationStrategy ?? "unknown"}`);
|
|
61836
|
+
if (pred.position) {
|
|
61837
|
+
lines.push(` Position: ${pred.position}`);
|
|
61838
|
+
}
|
|
61839
|
+
if (pred.dependencies.length > 0) {
|
|
61840
|
+
lines.push(` Dependencies (${pred.dependencies.length}):`);
|
|
61841
|
+
for (const dep of pred.dependencies) {
|
|
61842
|
+
lines.push(` - ${dep}`);
|
|
61843
|
+
}
|
|
61844
|
+
}
|
|
61845
|
+
if (pred.raSteps && pred.raSteps.length > 0) {
|
|
61846
|
+
lines.push(` RA operations (${pred.raSteps.length} steps):`);
|
|
61847
|
+
for (const step of pred.raSteps) {
|
|
61848
|
+
lines.push(` ${step}`);
|
|
61849
|
+
}
|
|
61850
|
+
}
|
|
61851
|
+
if (pred.pipelineStages && pred.pipelineStages.length > 0) {
|
|
61852
|
+
lines.push(` Pipeline stages (${pred.pipelineStages.length}):`);
|
|
61853
|
+
for (let pIdx = 0; pIdx < pred.pipelineStages.length; pIdx++) {
|
|
61854
|
+
const stage = pred.pipelineStages[pIdx];
|
|
61855
|
+
const countsStr = stage.counts.length > 0 ? `counts=[${stage.counts.join(", ")}]` : "counts=[]";
|
|
61856
|
+
lines.push(` [${pIdx + 1}] ${stage.durationMs.toFixed(2)}ms -> ${stage.resultSize} tuples (${countsStr})`);
|
|
61857
|
+
}
|
|
61858
|
+
}
|
|
61739
61859
|
lines.push("");
|
|
61740
|
-
|
|
61860
|
+
const endLine = lines.length;
|
|
61861
|
+
const key = `${qIdx}:${pred.predicateName}`;
|
|
61862
|
+
lineIndex.set(key, { start: startLine, end: endLine });
|
|
61863
|
+
}
|
|
61741
61864
|
}
|
|
61742
|
-
lines.
|
|
61743
|
-
lines.push(
|
|
61744
|
-
" classDef default fill:#e1f5ff,stroke:#333,stroke-width:2px"
|
|
61745
|
-
);
|
|
61746
|
-
lines.push(
|
|
61747
|
-
" classDef query fill:#ffe1e1,stroke:#333,stroke-width:3px"
|
|
61748
|
-
);
|
|
61749
|
-
lines.push(" class QUERY query");
|
|
61750
|
-
lines.push("```");
|
|
61751
|
-
return lines.join("\n");
|
|
61752
|
-
}
|
|
61753
|
-
function sanitizeMermaid(text) {
|
|
61754
|
-
return text.replace(/[<>"]/g, "");
|
|
61865
|
+
return { content: lines.join("\n"), lineIndex };
|
|
61755
61866
|
}
|
|
61756
|
-
function
|
|
61757
|
-
|
|
61758
|
-
|
|
61759
|
-
|
|
61760
|
-
|
|
61761
|
-
|
|
61762
|
-
sections.push("");
|
|
61763
|
-
sections.push("Output Files:");
|
|
61764
|
-
for (const f of outputFiles) {
|
|
61765
|
-
sections.push(` - ${f}`);
|
|
61766
|
-
}
|
|
61767
|
-
sections.push("");
|
|
61768
|
-
sections.push(`Log Format: ${profile.logFormat}`);
|
|
61769
|
-
if (profile.codeqlVersion) {
|
|
61770
|
-
sections.push(`CodeQL Version: ${profile.codeqlVersion}`);
|
|
61771
|
-
}
|
|
61772
|
-
sections.push(`Total Events: ${profile.totalEvents}`);
|
|
61773
|
-
sections.push(`Queries: ${profile.queries.length}`);
|
|
61774
|
-
for (const query of profile.queries) {
|
|
61775
|
-
sections.push("");
|
|
61776
|
-
sections.push(`--- ${basename4(query.queryName)} ---`);
|
|
61777
|
-
sections.push(` Total Duration: ${query.totalDurationMs.toFixed(2)} ms`);
|
|
61778
|
-
sections.push(` Predicates Evaluated: ${query.predicateCount}`);
|
|
61779
|
-
sections.push(` Cache Hits: ${query.cacheHits}`);
|
|
61867
|
+
function buildInlineResponse(profile, topN, detailLineIndex, files) {
|
|
61868
|
+
const queries = profile.queries.map((query, qIdx) => {
|
|
61869
|
+
const evalOrderMap = /* @__PURE__ */ new Map();
|
|
61870
|
+
query.predicates.forEach((pred, idx) => {
|
|
61871
|
+
evalOrderMap.set(pred, idx + 1);
|
|
61872
|
+
});
|
|
61780
61873
|
const top = getTopPredicates(query.predicates, topN);
|
|
61781
|
-
|
|
61782
|
-
|
|
61783
|
-
|
|
61784
|
-
|
|
61785
|
-
|
|
61786
|
-
|
|
61787
|
-
|
|
61788
|
-
|
|
61789
|
-
|
|
61790
|
-
|
|
61791
|
-
|
|
61874
|
+
return {
|
|
61875
|
+
queryName: query.queryName,
|
|
61876
|
+
totalDurationMs: query.totalDurationMs,
|
|
61877
|
+
predicateCount: query.predicateCount,
|
|
61878
|
+
cacheHits: query.cacheHits,
|
|
61879
|
+
slowestPredicates: top.map((pred) => {
|
|
61880
|
+
const key = `${qIdx}:${pred.predicateName}`;
|
|
61881
|
+
const detailLines = detailLineIndex.get(key) ?? { start: 0, end: 0 };
|
|
61882
|
+
return {
|
|
61883
|
+
evalOrder: evalOrderMap.get(pred) ?? 0,
|
|
61884
|
+
name: pred.predicateName,
|
|
61885
|
+
durationMs: pred.durationMs,
|
|
61886
|
+
resultSize: pred.resultSize,
|
|
61887
|
+
strategy: pred.evaluationStrategy,
|
|
61888
|
+
dependencyCount: pred.dependencies.length,
|
|
61889
|
+
pipelineCount: pred.pipelineCount,
|
|
61890
|
+
detailLines
|
|
61891
|
+
};
|
|
61892
|
+
})
|
|
61893
|
+
};
|
|
61894
|
+
});
|
|
61895
|
+
return {
|
|
61896
|
+
logFormat: profile.logFormat,
|
|
61897
|
+
codeqlVersion: profile.codeqlVersion,
|
|
61898
|
+
totalEvents: profile.totalEvents,
|
|
61899
|
+
queries,
|
|
61900
|
+
detailFile: files.detailFile,
|
|
61901
|
+
fullProfileJson: files.fullProfileJson,
|
|
61902
|
+
evaluatorLog: files.evaluatorLog
|
|
61903
|
+
};
|
|
61792
61904
|
}
|
|
61793
61905
|
function registerProfileCodeQLQueryFromLogsTool(server) {
|
|
61794
61906
|
server.tool(
|
|
61795
61907
|
"profile_codeql_query_from_logs",
|
|
61796
|
-
"Parse CodeQL
|
|
61908
|
+
"Parse CodeQL evaluator logs into a structured performance profile. Returns compact JSON with per-query summaries and top-N slowest predicates (name, duration, result size, eval order, dependency count). Full RA operations, pipeline-stage tuple progressions, and dependency lists are written to a line-indexed detail file \u2014 each predicate includes detailLines: {start, end} for targeted read_file access to its full analysis. Works with logs from codeql query run, codeql database analyze, or vscode-codeql.",
|
|
61797
61909
|
{
|
|
61798
61910
|
evaluatorLog: external_exports.string().describe(
|
|
61799
61911
|
"Path to evaluator-log.jsonl or evaluator-log.summary.jsonl"
|
|
@@ -61802,7 +61914,7 @@ function registerProfileCodeQLQueryFromLogsTool(server) {
|
|
|
61802
61914
|
"Directory to write profile output files (defaults to same directory as log)"
|
|
61803
61915
|
),
|
|
61804
61916
|
topN: external_exports.number().optional().describe(
|
|
61805
|
-
"Number of
|
|
61917
|
+
"Number of slowest predicates to include per query (default: 20)"
|
|
61806
61918
|
)
|
|
61807
61919
|
},
|
|
61808
61920
|
async (params) => {
|
|
@@ -61814,51 +61926,42 @@ function registerProfileCodeQLQueryFromLogsTool(server) {
|
|
|
61814
61926
|
content: [
|
|
61815
61927
|
{
|
|
61816
61928
|
type: "text",
|
|
61817
|
-
text: `Evaluator log not found at: ${evaluatorLog}`
|
|
61929
|
+
text: JSON.stringify({ error: `Evaluator log not found at: ${evaluatorLog}` })
|
|
61818
61930
|
}
|
|
61819
61931
|
],
|
|
61820
61932
|
isError: true
|
|
61821
61933
|
};
|
|
61822
61934
|
}
|
|
61823
61935
|
logger.info(`Parsing evaluator log from: ${evaluatorLog}`);
|
|
61824
|
-
const profile = parseEvaluatorLog(evaluatorLog);
|
|
61936
|
+
const profile = await parseEvaluatorLog(evaluatorLog);
|
|
61825
61937
|
const profileOutputDir = outputDir ?? dirname6(evaluatorLog);
|
|
61826
61938
|
mkdirSync6(profileOutputDir, { recursive: true });
|
|
61827
|
-
const jsonPath = join11(
|
|
61828
|
-
|
|
61829
|
-
|
|
61830
|
-
);
|
|
61831
|
-
|
|
61832
|
-
|
|
61833
|
-
|
|
61834
|
-
|
|
61835
|
-
|
|
61836
|
-
|
|
61837
|
-
|
|
61838
|
-
|
|
61839
|
-
const outputFilesList = [
|
|
61840
|
-
`Profile JSON: ${jsonPath}`,
|
|
61841
|
-
`Profile Mermaid: ${mdPath}`,
|
|
61842
|
-
`Evaluator Log: ${evaluatorLog}`
|
|
61843
|
-
];
|
|
61844
|
-
const responseText = buildTextSummary(
|
|
61845
|
-
profile,
|
|
61846
|
-
effectiveTopN,
|
|
61847
|
-
outputFilesList
|
|
61848
|
-
);
|
|
61939
|
+
const jsonPath = join11(profileOutputDir, "query-evaluation-profile.json");
|
|
61940
|
+
writeFileSync3(jsonPath, JSON.stringify(profile, null, 2));
|
|
61941
|
+
logger.info(`Full profile JSON written to: ${jsonPath}`);
|
|
61942
|
+
const { content: detailContent, lineIndex } = buildDetailFile(profile, effectiveTopN);
|
|
61943
|
+
const detailPath = join11(profileOutputDir, "query-evaluation-detail.txt");
|
|
61944
|
+
writeFileSync3(detailPath, detailContent);
|
|
61945
|
+
logger.info(`Detail file written to: ${detailPath}`);
|
|
61946
|
+
const response = buildInlineResponse(profile, effectiveTopN, lineIndex, {
|
|
61947
|
+
detailFile: detailPath,
|
|
61948
|
+
fullProfileJson: jsonPath,
|
|
61949
|
+
evaluatorLog
|
|
61950
|
+
});
|
|
61849
61951
|
return {
|
|
61850
|
-
content: [
|
|
61952
|
+
content: [
|
|
61953
|
+
{ type: "text", text: JSON.stringify(response) }
|
|
61954
|
+
]
|
|
61851
61955
|
};
|
|
61852
61956
|
} catch (error2) {
|
|
61853
|
-
logger.error(
|
|
61854
|
-
"Error profiling CodeQL query from logs:",
|
|
61855
|
-
error2
|
|
61856
|
-
);
|
|
61957
|
+
logger.error("Error profiling CodeQL query from logs:", error2);
|
|
61857
61958
|
return {
|
|
61858
61959
|
content: [
|
|
61859
61960
|
{
|
|
61860
61961
|
type: "text",
|
|
61861
|
-
text:
|
|
61962
|
+
text: JSON.stringify({
|
|
61963
|
+
error: `Failed to profile query from logs: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
61964
|
+
})
|
|
61862
61965
|
}
|
|
61863
61966
|
],
|
|
61864
61967
|
isError: true
|
|
@@ -61871,76 +61974,114 @@ function registerProfileCodeQLQueryFromLogsTool(server) {
|
|
|
61871
61974
|
// src/tools/codeql/profile-codeql-query.ts
|
|
61872
61975
|
init_cli_executor();
|
|
61873
61976
|
init_logger();
|
|
61874
|
-
import { writeFileSync as writeFileSync4,
|
|
61977
|
+
import { writeFileSync as writeFileSync4, existsSync as existsSync10 } from "fs";
|
|
61978
|
+
import { createReadStream as createReadStream2 } from "fs";
|
|
61875
61979
|
import { join as join12, dirname as dirname7, basename as basename5 } from "path";
|
|
61876
61980
|
import { mkdirSync as mkdirSync7 } from "fs";
|
|
61877
|
-
|
|
61878
|
-
|
|
61879
|
-
const jsonObjects = logContent.split("\n\n").filter((s) => s.trim());
|
|
61880
|
-
const events = jsonObjects.map((obj) => {
|
|
61881
|
-
try {
|
|
61882
|
-
return JSON.parse(obj);
|
|
61883
|
-
} catch (_error) {
|
|
61884
|
-
logger.warn(`Failed to parse evaluator log object: ${obj.substring(0, 100)}...`);
|
|
61885
|
-
return null;
|
|
61886
|
-
}
|
|
61887
|
-
}).filter((event) => event !== null);
|
|
61981
|
+
import { createInterface as createInterface2 } from "readline";
|
|
61982
|
+
async function parseEvaluatorLog2(logPath) {
|
|
61888
61983
|
const pipelineMap = /* @__PURE__ */ new Map();
|
|
61889
61984
|
const predicateNameToEventId = /* @__PURE__ */ new Map();
|
|
61985
|
+
const predicateStartNanoTimes = /* @__PURE__ */ new Map();
|
|
61890
61986
|
let queryName = "";
|
|
61891
61987
|
let queryStartTime = 0;
|
|
61892
61988
|
let queryEndTime = 0;
|
|
61893
|
-
|
|
61894
|
-
|
|
61895
|
-
|
|
61896
|
-
|
|
61897
|
-
|
|
61898
|
-
|
|
61899
|
-
|
|
61900
|
-
|
|
61901
|
-
|
|
61902
|
-
|
|
61903
|
-
|
|
61904
|
-
|
|
61905
|
-
|
|
61906
|
-
|
|
61907
|
-
|
|
61908
|
-
|
|
61909
|
-
|
|
61910
|
-
|
|
61911
|
-
|
|
61912
|
-
|
|
61913
|
-
|
|
61914
|
-
|
|
61915
|
-
|
|
61989
|
+
let totalEvents = 0;
|
|
61990
|
+
const rl = createInterface2({
|
|
61991
|
+
input: createReadStream2(logPath, { encoding: "utf-8" }),
|
|
61992
|
+
crlfDelay: Infinity
|
|
61993
|
+
});
|
|
61994
|
+
let depth = 0;
|
|
61995
|
+
let inString = false;
|
|
61996
|
+
let escape2 = false;
|
|
61997
|
+
const lines = [];
|
|
61998
|
+
for await (const line of rl) {
|
|
61999
|
+
for (const ch of line) {
|
|
62000
|
+
if (escape2) {
|
|
62001
|
+
escape2 = false;
|
|
62002
|
+
continue;
|
|
62003
|
+
}
|
|
62004
|
+
if (ch === "\\" && inString) {
|
|
62005
|
+
escape2 = true;
|
|
62006
|
+
continue;
|
|
62007
|
+
}
|
|
62008
|
+
if (ch === '"') {
|
|
62009
|
+
inString = !inString;
|
|
62010
|
+
continue;
|
|
62011
|
+
}
|
|
62012
|
+
if (inString) continue;
|
|
62013
|
+
if (ch === "{") depth++;
|
|
62014
|
+
if (ch === "}") depth--;
|
|
62015
|
+
}
|
|
62016
|
+
if (depth > 0 || depth === 0 && line.trim().length > 0 && lines.length > 0) {
|
|
62017
|
+
lines.push(line);
|
|
62018
|
+
} else if (depth === 0 && lines.length === 0 && line.trim().length > 0) {
|
|
62019
|
+
lines.push(line);
|
|
62020
|
+
}
|
|
62021
|
+
if (depth === 0 && lines.length > 0) {
|
|
62022
|
+
const objStr = lines.join("\n");
|
|
62023
|
+
lines.length = 0;
|
|
62024
|
+
inString = false;
|
|
62025
|
+
escape2 = false;
|
|
62026
|
+
if (objStr.trim().length === 0) continue;
|
|
62027
|
+
let event;
|
|
62028
|
+
try {
|
|
62029
|
+
event = JSON.parse(objStr);
|
|
62030
|
+
} catch {
|
|
62031
|
+
logger.warn(`Failed to parse evaluator log object: ${objStr.substring(0, 100)}...`);
|
|
62032
|
+
continue;
|
|
62033
|
+
}
|
|
62034
|
+
totalEvents++;
|
|
62035
|
+
switch (event.type) {
|
|
62036
|
+
case "QUERY_STARTED":
|
|
62037
|
+
queryName = event.queryName || "";
|
|
62038
|
+
queryStartTime = event.nanoTime;
|
|
62039
|
+
break;
|
|
62040
|
+
case "QUERY_COMPLETED":
|
|
62041
|
+
queryEndTime = event.nanoTime;
|
|
62042
|
+
break;
|
|
62043
|
+
case "PREDICATE_STARTED": {
|
|
62044
|
+
const predicateName = event.predicateName;
|
|
62045
|
+
const position = event.position;
|
|
62046
|
+
const predicateType = event.predicateType;
|
|
62047
|
+
const dependencies = event.dependencies;
|
|
62048
|
+
predicateNameToEventId.set(predicateName, event.eventId);
|
|
62049
|
+
predicateStartNanoTimes.set(event.eventId, event.nanoTime);
|
|
62050
|
+
const dependencyEventIds = [];
|
|
62051
|
+
const dependencyNames = [];
|
|
62052
|
+
if (dependencies) {
|
|
62053
|
+
for (const depName of Object.keys(dependencies)) {
|
|
62054
|
+
dependencyNames.push(depName);
|
|
62055
|
+
const depEventId = predicateNameToEventId.get(depName);
|
|
62056
|
+
if (depEventId !== void 0) {
|
|
62057
|
+
dependencyEventIds.push(depEventId);
|
|
62058
|
+
}
|
|
61916
62059
|
}
|
|
61917
62060
|
}
|
|
62061
|
+
pipelineMap.set(event.eventId, {
|
|
62062
|
+
eventId: event.eventId,
|
|
62063
|
+
name: predicateName,
|
|
62064
|
+
position,
|
|
62065
|
+
type: predicateType,
|
|
62066
|
+
startTime: event.nanoTime,
|
|
62067
|
+
dependencies: dependencyNames,
|
|
62068
|
+
dependencyEventIds
|
|
62069
|
+
});
|
|
62070
|
+
break;
|
|
61918
62071
|
}
|
|
61919
|
-
|
|
61920
|
-
|
|
61921
|
-
|
|
61922
|
-
|
|
61923
|
-
|
|
61924
|
-
|
|
61925
|
-
dependencies: dependencyNames,
|
|
61926
|
-
dependencyEventIds
|
|
61927
|
-
});
|
|
61928
|
-
break;
|
|
61929
|
-
}
|
|
61930
|
-
case "PREDICATE_COMPLETED": {
|
|
61931
|
-
const startEventId = event.startEvent;
|
|
61932
|
-
const pipelineInfo = pipelineMap.get(startEventId);
|
|
61933
|
-
if (pipelineInfo) {
|
|
61934
|
-
const startEvent = events.find((e) => e.eventId === startEventId);
|
|
61935
|
-
if (startEvent) {
|
|
61936
|
-
const duration3 = (event.nanoTime - startEvent.nanoTime) / 1e6;
|
|
62072
|
+
case "PREDICATE_COMPLETED": {
|
|
62073
|
+
const startEventId = event.startEvent;
|
|
62074
|
+
const pipelineInfo = pipelineMap.get(startEventId);
|
|
62075
|
+
const startNano = predicateStartNanoTimes.get(startEventId);
|
|
62076
|
+
if (pipelineInfo && startNano !== void 0) {
|
|
62077
|
+
const duration3 = (event.nanoTime - startNano) / 1e6;
|
|
61937
62078
|
pipelineInfo.endTime = event.nanoTime;
|
|
61938
62079
|
pipelineInfo.duration = duration3;
|
|
61939
62080
|
pipelineInfo.resultSize = event.resultSize;
|
|
61940
62081
|
pipelineInfo.tupleCount = event.tupleCount;
|
|
61941
62082
|
}
|
|
62083
|
+
break;
|
|
61942
62084
|
}
|
|
61943
|
-
break;
|
|
61944
62085
|
}
|
|
61945
62086
|
}
|
|
61946
62087
|
}
|
|
@@ -61949,14 +62090,14 @@ function parseEvaluatorLog2(logPath) {
|
|
|
61949
62090
|
return {
|
|
61950
62091
|
queryName,
|
|
61951
62092
|
totalDuration,
|
|
61952
|
-
totalEvents
|
|
62093
|
+
totalEvents,
|
|
61953
62094
|
pipelines
|
|
61954
62095
|
};
|
|
61955
62096
|
}
|
|
61956
|
-
function
|
|
62097
|
+
function formatAsJson(profile) {
|
|
61957
62098
|
return JSON.stringify(profile, null, 2);
|
|
61958
62099
|
}
|
|
61959
|
-
function
|
|
62100
|
+
function formatAsMermaid(profile) {
|
|
61960
62101
|
const lines = [];
|
|
61961
62102
|
lines.push("```mermaid");
|
|
61962
62103
|
lines.push("graph TD");
|
|
@@ -62063,15 +62204,15 @@ function registerProfileCodeQLQueryTool(server) {
|
|
|
62063
62204
|
};
|
|
62064
62205
|
}
|
|
62065
62206
|
logger.info(`Parsing evaluator log from: ${logPath}`);
|
|
62066
|
-
const profile = parseEvaluatorLog2(logPath);
|
|
62207
|
+
const profile = await parseEvaluatorLog2(logPath);
|
|
62067
62208
|
const profileOutputDir = outputDir || dirname7(logPath);
|
|
62068
62209
|
mkdirSync7(profileOutputDir, { recursive: true });
|
|
62069
62210
|
const jsonPath = join12(profileOutputDir, "query-evaluation-profile.json");
|
|
62070
|
-
const jsonContent =
|
|
62211
|
+
const jsonContent = formatAsJson(profile);
|
|
62071
62212
|
writeFileSync4(jsonPath, jsonContent);
|
|
62072
62213
|
logger.info(`Profile JSON written to: ${jsonPath}`);
|
|
62073
62214
|
const mdPath = join12(profileOutputDir, "query-evaluation-profile.md");
|
|
62074
|
-
const mdContent =
|
|
62215
|
+
const mdContent = formatAsMermaid(profile);
|
|
62075
62216
|
writeFileSync4(mdPath, mdContent);
|
|
62076
62217
|
logger.info(`Profile Mermaid diagram written to: ${mdPath}`);
|
|
62077
62218
|
const outputFiles = [
|
|
@@ -62280,7 +62421,7 @@ function registerQuickEvaluateTool(server) {
|
|
|
62280
62421
|
|
|
62281
62422
|
// src/tools/codeql/read-database-source.ts
|
|
62282
62423
|
var import_adm_zip = __toESM(require_adm_zip(), 1);
|
|
62283
|
-
import { existsSync as existsSync11, readdirSync as
|
|
62424
|
+
import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as readFileSync8, statSync as statSync7 } from "fs";
|
|
62284
62425
|
import { join as join14, resolve as resolve7 } from "path";
|
|
62285
62426
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
62286
62427
|
init_logger();
|
|
@@ -62297,9 +62438,9 @@ function toFilesystemPath(uri) {
|
|
|
62297
62438
|
return uri;
|
|
62298
62439
|
}
|
|
62299
62440
|
function* walkDirectory(dir, base = dir) {
|
|
62300
|
-
for (const entry of
|
|
62441
|
+
for (const entry of readdirSync7(dir)) {
|
|
62301
62442
|
const fullPath = join14(dir, entry);
|
|
62302
|
-
if (
|
|
62443
|
+
if (statSync7(fullPath).isDirectory()) {
|
|
62303
62444
|
yield* walkDirectory(fullPath, base);
|
|
62304
62445
|
} else {
|
|
62305
62446
|
yield fullPath.slice(base.length).replace(/\\/g, "/").replace(/^\//, "");
|
|
@@ -62442,7 +62583,7 @@ Directory contains ${availableEntries.length} entries. Use read_database_source
|
|
|
62442
62583
|
);
|
|
62443
62584
|
}
|
|
62444
62585
|
const fullPath = join14(srcDirPath, matchedRelative);
|
|
62445
|
-
const rawContent =
|
|
62586
|
+
const rawContent = readFileSync8(fullPath, "utf-8");
|
|
62446
62587
|
const { content, effectiveEnd, effectiveStart, totalLines } = applyLineRange(
|
|
62447
62588
|
rawContent,
|
|
62448
62589
|
startLine,
|
|
@@ -62601,6 +62742,32 @@ var codeqlResolveDatabaseTool = {
|
|
|
62601
62742
|
resultProcessor: defaultCLIResultProcessor
|
|
62602
62743
|
};
|
|
62603
62744
|
|
|
62745
|
+
// src/tools/codeql/resolve-files.ts
|
|
62746
|
+
var codeqlResolveFilesTool = {
|
|
62747
|
+
name: "codeql_resolve_files",
|
|
62748
|
+
description: "Find files in a directory tree, filtered by extension and glob patterns. Useful for discovering QL library files, query files, and other CodeQL-related files within packs or workspaces.",
|
|
62749
|
+
command: "codeql",
|
|
62750
|
+
subcommand: "resolve files",
|
|
62751
|
+
inputSchema: {
|
|
62752
|
+
dir: external_exports.string().describe("The directory to search for files"),
|
|
62753
|
+
"include-extension": external_exports.array(external_exports.string()).optional().describe("Include files with given extensions (e.g., ['.qll', '.ql'])"),
|
|
62754
|
+
include: external_exports.array(external_exports.string()).optional().describe("Glob patterns to include (e.g., ['**/RemoteFlowSource*'])"),
|
|
62755
|
+
exclude: external_exports.array(external_exports.string()).optional().describe("Glob patterns to exclude"),
|
|
62756
|
+
prune: external_exports.array(external_exports.string()).optional().describe("Glob patterns for directories to prune from search"),
|
|
62757
|
+
"also-match": external_exports.array(external_exports.string()).optional().describe("Additional glob filter all results must match"),
|
|
62758
|
+
format: external_exports.enum(["text", "json"]).optional().describe("Output format (default: text)"),
|
|
62759
|
+
"follow-symlinks": external_exports.boolean().optional().describe("Follow symlinks when searching"),
|
|
62760
|
+
additionalArgs: createCodeQLSchemas.additionalArgs()
|
|
62761
|
+
},
|
|
62762
|
+
examples: [
|
|
62763
|
+
"codeql resolve files --include-extension=.qll --format=json -- /path/to/pack",
|
|
62764
|
+
"codeql resolve files --include=**/RemoteFlowSource* -- /path/to/pack",
|
|
62765
|
+
"codeql resolve files --include-extension=.ql --include-extension=.qll -- /path/to/pack",
|
|
62766
|
+
"codeql resolve files --include-extension=.qll --also-match=**/FlowSource* -- /path/to/pack"
|
|
62767
|
+
],
|
|
62768
|
+
resultProcessor: defaultCLIResultProcessor
|
|
62769
|
+
};
|
|
62770
|
+
|
|
62604
62771
|
// src/tools/codeql/resolve-languages.ts
|
|
62605
62772
|
var codeqlResolveLanguagesTool = {
|
|
62606
62773
|
name: "codeql_resolve_languages",
|
|
@@ -62745,6 +62912,255 @@ var codeqlResolveTestsTool = {
|
|
|
62745
62912
|
resultProcessor: defaultCLIResultProcessor
|
|
62746
62913
|
};
|
|
62747
62914
|
|
|
62915
|
+
// src/tools/codeql/search-ql-code.ts
|
|
62916
|
+
import { closeSync, createReadStream as createReadStream3, fstatSync, lstatSync, openSync, readdirSync as readdirSync8, readFileSync as readFileSync9, realpathSync } from "fs";
|
|
62917
|
+
import { basename as basename6, extname as extname2, join as join15, resolve as resolve9 } from "path";
|
|
62918
|
+
import { createInterface as createInterface3 } from "readline";
|
|
62919
|
+
init_logger();
|
|
62920
|
+
var MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
|
|
62921
|
+
var MAX_FILES_TRAVERSED = 1e4;
|
|
62922
|
+
var MAX_CONTEXT_LINES = 50;
|
|
62923
|
+
var MAX_MAX_RESULTS = 1e4;
|
|
62924
|
+
var SKIP_DIRS2 = /* @__PURE__ */ new Set([".codeql", "node_modules", ".git"]);
|
|
62925
|
+
function collectFiles(paths, extensions, fileCount) {
|
|
62926
|
+
const files = [];
|
|
62927
|
+
const visitedDirs = /* @__PURE__ */ new Set();
|
|
62928
|
+
function walk(p) {
|
|
62929
|
+
if (fileCount.value >= MAX_FILES_TRAVERSED) return;
|
|
62930
|
+
let stat;
|
|
62931
|
+
try {
|
|
62932
|
+
stat = lstatSync(p);
|
|
62933
|
+
} catch {
|
|
62934
|
+
return;
|
|
62935
|
+
}
|
|
62936
|
+
if (stat.isSymbolicLink()) return;
|
|
62937
|
+
if (stat.isFile()) {
|
|
62938
|
+
if (extensions.length === 0 || extensions.includes(extname2(p))) {
|
|
62939
|
+
files.push(p);
|
|
62940
|
+
}
|
|
62941
|
+
fileCount.value++;
|
|
62942
|
+
} else if (stat.isDirectory()) {
|
|
62943
|
+
if (SKIP_DIRS2.has(basename6(p))) return;
|
|
62944
|
+
let realPath;
|
|
62945
|
+
try {
|
|
62946
|
+
realPath = realpathSync(p);
|
|
62947
|
+
} catch {
|
|
62948
|
+
return;
|
|
62949
|
+
}
|
|
62950
|
+
if (visitedDirs.has(realPath)) return;
|
|
62951
|
+
visitedDirs.add(realPath);
|
|
62952
|
+
let entries;
|
|
62953
|
+
try {
|
|
62954
|
+
entries = readdirSync8(p);
|
|
62955
|
+
} catch {
|
|
62956
|
+
return;
|
|
62957
|
+
}
|
|
62958
|
+
for (const entry of entries) {
|
|
62959
|
+
if (fileCount.value >= MAX_FILES_TRAVERSED) return;
|
|
62960
|
+
walk(join15(p, entry));
|
|
62961
|
+
}
|
|
62962
|
+
}
|
|
62963
|
+
}
|
|
62964
|
+
for (const p of paths) {
|
|
62965
|
+
if (fileCount.value >= MAX_FILES_TRAVERSED) break;
|
|
62966
|
+
walk(resolve9(p));
|
|
62967
|
+
}
|
|
62968
|
+
return files;
|
|
62969
|
+
}
|
|
62970
|
+
async function searchFile(filePath, regex, contextLines, maxCollect) {
|
|
62971
|
+
let fd;
|
|
62972
|
+
try {
|
|
62973
|
+
fd = openSync(filePath, "r");
|
|
62974
|
+
} catch {
|
|
62975
|
+
return { matches: [], totalCount: 0 };
|
|
62976
|
+
}
|
|
62977
|
+
let size;
|
|
62978
|
+
try {
|
|
62979
|
+
size = fstatSync(fd).size;
|
|
62980
|
+
} catch {
|
|
62981
|
+
try {
|
|
62982
|
+
closeSync(fd);
|
|
62983
|
+
} catch {
|
|
62984
|
+
}
|
|
62985
|
+
return { matches: [], totalCount: 0 };
|
|
62986
|
+
}
|
|
62987
|
+
if (size > MAX_FILE_SIZE_BYTES) {
|
|
62988
|
+
return searchFileStreaming(filePath, regex, contextLines, maxCollect, fd);
|
|
62989
|
+
}
|
|
62990
|
+
let content;
|
|
62991
|
+
try {
|
|
62992
|
+
content = readFileSync9(fd, "utf-8");
|
|
62993
|
+
} catch {
|
|
62994
|
+
try {
|
|
62995
|
+
closeSync(fd);
|
|
62996
|
+
} catch {
|
|
62997
|
+
}
|
|
62998
|
+
return { matches: [], totalCount: 0 };
|
|
62999
|
+
}
|
|
63000
|
+
try {
|
|
63001
|
+
closeSync(fd);
|
|
63002
|
+
} catch {
|
|
63003
|
+
}
|
|
63004
|
+
const lines = content.replace(/\r\n/g, "\n").split("\n");
|
|
63005
|
+
const matches = [];
|
|
63006
|
+
let totalCount = 0;
|
|
63007
|
+
for (let i = 0; i < lines.length; i++) {
|
|
63008
|
+
if (regex.test(lines[i])) {
|
|
63009
|
+
totalCount++;
|
|
63010
|
+
if (matches.length < maxCollect) {
|
|
63011
|
+
const match = {
|
|
63012
|
+
filePath,
|
|
63013
|
+
lineNumber: i + 1,
|
|
63014
|
+
lineContent: lines[i]
|
|
63015
|
+
};
|
|
63016
|
+
if (contextLines > 0) {
|
|
63017
|
+
const beforeStart = Math.max(0, i - contextLines);
|
|
63018
|
+
const afterEnd = Math.min(lines.length - 1, i + contextLines);
|
|
63019
|
+
match.contextBefore = lines.slice(beforeStart, i);
|
|
63020
|
+
match.contextAfter = lines.slice(i + 1, afterEnd + 1);
|
|
63021
|
+
}
|
|
63022
|
+
matches.push(match);
|
|
63023
|
+
}
|
|
63024
|
+
}
|
|
63025
|
+
}
|
|
63026
|
+
return { matches, totalCount };
|
|
63027
|
+
}
|
|
63028
|
+
async function searchFileStreaming(filePath, regex, contextLines, maxCollect, fd) {
|
|
63029
|
+
const matches = [];
|
|
63030
|
+
const recentLines = [];
|
|
63031
|
+
const pending = [];
|
|
63032
|
+
let lineNumber = 0;
|
|
63033
|
+
let totalCount = 0;
|
|
63034
|
+
let rl;
|
|
63035
|
+
try {
|
|
63036
|
+
const streamOpts = { encoding: "utf-8" };
|
|
63037
|
+
if (fd !== void 0) {
|
|
63038
|
+
streamOpts.fd = fd;
|
|
63039
|
+
streamOpts.autoClose = true;
|
|
63040
|
+
streamOpts.start = 0;
|
|
63041
|
+
}
|
|
63042
|
+
rl = createInterface3({
|
|
63043
|
+
input: createReadStream3(filePath, streamOpts),
|
|
63044
|
+
crlfDelay: Infinity
|
|
63045
|
+
});
|
|
63046
|
+
} catch {
|
|
63047
|
+
if (fd !== void 0) {
|
|
63048
|
+
try {
|
|
63049
|
+
closeSync(fd);
|
|
63050
|
+
} catch {
|
|
63051
|
+
}
|
|
63052
|
+
}
|
|
63053
|
+
return { matches: [], totalCount: 0 };
|
|
63054
|
+
}
|
|
63055
|
+
for await (const line of rl) {
|
|
63056
|
+
lineNumber++;
|
|
63057
|
+
for (const p of pending) {
|
|
63058
|
+
if (p.afterNeeded > 0) {
|
|
63059
|
+
p.match.contextAfter.push(line);
|
|
63060
|
+
p.afterNeeded--;
|
|
63061
|
+
}
|
|
63062
|
+
}
|
|
63063
|
+
while (pending.length > 0 && pending[0].afterNeeded === 0) {
|
|
63064
|
+
pending.shift();
|
|
63065
|
+
}
|
|
63066
|
+
if (regex.test(line)) {
|
|
63067
|
+
totalCount++;
|
|
63068
|
+
if (matches.length < maxCollect) {
|
|
63069
|
+
const match = {
|
|
63070
|
+
filePath,
|
|
63071
|
+
lineNumber,
|
|
63072
|
+
lineContent: line
|
|
63073
|
+
};
|
|
63074
|
+
if (contextLines > 0) {
|
|
63075
|
+
match.contextBefore = recentLines.slice(-contextLines);
|
|
63076
|
+
match.contextAfter = [];
|
|
63077
|
+
pending.push({ match, afterNeeded: contextLines });
|
|
63078
|
+
}
|
|
63079
|
+
matches.push(match);
|
|
63080
|
+
}
|
|
63081
|
+
}
|
|
63082
|
+
if (contextLines > 0) {
|
|
63083
|
+
recentLines.push(line);
|
|
63084
|
+
if (recentLines.length > contextLines) {
|
|
63085
|
+
recentLines.shift();
|
|
63086
|
+
}
|
|
63087
|
+
}
|
|
63088
|
+
}
|
|
63089
|
+
return { matches, totalCount };
|
|
63090
|
+
}
|
|
63091
|
+
async function searchQlCode(params) {
|
|
63092
|
+
const {
|
|
63093
|
+
pattern,
|
|
63094
|
+
paths,
|
|
63095
|
+
includeExtensions = [".ql", ".qll"],
|
|
63096
|
+
caseSensitive = true,
|
|
63097
|
+
contextLines: rawContextLines = 0,
|
|
63098
|
+
maxResults: rawMaxResults = 100
|
|
63099
|
+
} = params;
|
|
63100
|
+
const contextLines = Math.min(Math.max(0, Math.floor(rawContextLines)), MAX_CONTEXT_LINES);
|
|
63101
|
+
const maxResults = Math.min(Math.max(1, Math.floor(rawMaxResults)), MAX_MAX_RESULTS);
|
|
63102
|
+
const flags = caseSensitive ? "" : "i";
|
|
63103
|
+
const regex = new RegExp(pattern, flags);
|
|
63104
|
+
const fileCount = { value: 0 };
|
|
63105
|
+
const filesToSearch = collectFiles(paths, includeExtensions, fileCount);
|
|
63106
|
+
const allMatches = [];
|
|
63107
|
+
let totalMatches = 0;
|
|
63108
|
+
for (const file of filesToSearch) {
|
|
63109
|
+
const remainingSlots = Math.max(0, maxResults - allMatches.length);
|
|
63110
|
+
const { matches: fileMatches, totalCount } = await searchFile(
|
|
63111
|
+
file,
|
|
63112
|
+
regex,
|
|
63113
|
+
contextLines,
|
|
63114
|
+
remainingSlots
|
|
63115
|
+
);
|
|
63116
|
+
totalMatches += totalCount;
|
|
63117
|
+
allMatches.push(...fileMatches);
|
|
63118
|
+
}
|
|
63119
|
+
return {
|
|
63120
|
+
results: allMatches,
|
|
63121
|
+
totalMatches,
|
|
63122
|
+
returnedMatches: allMatches.length,
|
|
63123
|
+
truncated: totalMatches > maxResults,
|
|
63124
|
+
filesSearched: filesToSearch.length
|
|
63125
|
+
};
|
|
63126
|
+
}
|
|
63127
|
+
function registerSearchQlCodeTool(server) {
|
|
63128
|
+
server.tool(
|
|
63129
|
+
"search_ql_code",
|
|
63130
|
+
"Search QL source files (.ql/.qll) for text or regex patterns. Returns structured results with file paths, line numbers, and optional context lines. Use this instead of grep for searching CodeQL source code.",
|
|
63131
|
+
{
|
|
63132
|
+
pattern: external_exports.string().describe("Text or regex pattern to search for (JavaScript regex syntax)"),
|
|
63133
|
+
paths: external_exports.array(external_exports.string()).min(1).describe("Directories or files to search in"),
|
|
63134
|
+
includeExtensions: external_exports.array(external_exports.string()).optional().default([".ql", ".qll"]).describe("File extensions to search (default: ['.ql', '.qll'])"),
|
|
63135
|
+
caseSensitive: external_exports.boolean().optional().default(true).describe("Whether search is case sensitive (default: true)"),
|
|
63136
|
+
contextLines: external_exports.number().int().min(0).max(MAX_CONTEXT_LINES).optional().default(0).describe("Lines of context before and after each match (default: 0, max: 50)"),
|
|
63137
|
+
maxResults: external_exports.number().int().min(1).max(MAX_MAX_RESULTS).optional().default(100).describe("Maximum number of matching lines to return (default: 100, max: 10000)")
|
|
63138
|
+
},
|
|
63139
|
+
async ({ pattern, paths, includeExtensions, caseSensitive, contextLines, maxResults }) => {
|
|
63140
|
+
try {
|
|
63141
|
+
const result = await searchQlCode({
|
|
63142
|
+
pattern,
|
|
63143
|
+
paths,
|
|
63144
|
+
includeExtensions,
|
|
63145
|
+
caseSensitive,
|
|
63146
|
+
contextLines,
|
|
63147
|
+
maxResults
|
|
63148
|
+
});
|
|
63149
|
+
return {
|
|
63150
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
63151
|
+
};
|
|
63152
|
+
} catch (error2) {
|
|
63153
|
+
logger.error("Error in search_ql_code:", error2);
|
|
63154
|
+
const message = error2 instanceof SyntaxError || error2 instanceof Error && error2.message.includes("Invalid regular expression") ? `Invalid regex pattern: ${error2.message}` : `Error: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
63155
|
+
return {
|
|
63156
|
+
content: [{ type: "text", text: message }],
|
|
63157
|
+
isError: true
|
|
63158
|
+
};
|
|
63159
|
+
}
|
|
63160
|
+
}
|
|
63161
|
+
);
|
|
63162
|
+
}
|
|
63163
|
+
|
|
62748
63164
|
// src/tools/codeql/test-accept.ts
|
|
62749
63165
|
var codeqlTestAcceptTool = {
|
|
62750
63166
|
name: "codeql_test_accept",
|
|
@@ -63015,6 +63431,7 @@ function registerCodeQLTools(server) {
|
|
|
63015
63431
|
registerCLITool(server, codeqlQueryFormatTool);
|
|
63016
63432
|
registerCLITool(server, codeqlQueryRunTool);
|
|
63017
63433
|
registerCLITool(server, codeqlResolveDatabaseTool);
|
|
63434
|
+
registerCLITool(server, codeqlResolveFilesTool);
|
|
63018
63435
|
registerCLITool(server, codeqlResolveLanguagesTool);
|
|
63019
63436
|
registerCLITool(server, codeqlResolveLibraryPathTool);
|
|
63020
63437
|
registerCLITool(server, codeqlResolveMetadataTool);
|
|
@@ -63035,6 +63452,7 @@ function registerCodeQLTools(server) {
|
|
|
63035
63452
|
registerQuickEvaluateTool(server);
|
|
63036
63453
|
registerReadDatabaseSourceTool(server);
|
|
63037
63454
|
registerRegisterDatabaseTool(server);
|
|
63455
|
+
registerSearchQlCodeTool(server);
|
|
63038
63456
|
}
|
|
63039
63457
|
|
|
63040
63458
|
// src/resources/dataflow-migration-v1-to-v2.md
|
|
@@ -63044,7 +63462,7 @@ var dataflow_migration_v1_to_v2_default = '# Dataflow API Migration: v1 to v2\n\
|
|
|
63044
63462
|
var learning_query_basics_default = '# Writing CodeQL Queries\n\nThis resource is a practical reference for writing CodeQL queries using the MCP server\'s tools. It covers query structure, metadata annotations, common QL patterns, compilation, testing, and the file conventions used by the CodeQL test framework.\n\n## Query Structure\n\nEvery CodeQL query has three main clauses:\n\n```ql\n/**\n * @name Descriptive name of what the query finds\n * @description Longer explanation of the vulnerability or pattern\n * @kind problem\n * @problem.severity warning\n * @precision medium\n * @id lang/query-id\n * @tags security\n * correctness\n */\n\nimport language\n\nfrom SourceType source, SinkType sink\nwhere <conditions linking source to sink>\nselect <result expression>, <message string>\n```\n\n### `from` Clause\n\nDeclares typed variables. Each variable ranges over all values of its type in the database:\n\n```ql\nfrom Function f, FunctionCall call\n```\n\n### `where` Clause\n\nFilters the cross-product of `from` variables using predicates:\n\n```ql\nwhere call.getTarget() = f\n and f.getName() = "eval"\n```\n\n### `select` Clause\n\nDefines the output columns. The first expression is the "element" (the location in source code), followed by a message string:\n\n```ql\nselect call, "Call to dangerous function " + f.getName()\n```\n\n## Metadata Annotations\n\nMetadata goes in a QLDoc comment block (`/** ... */`) at the top of the query file:\n\n| Annotation | Required | Description |\n| -------------------- | ---------------------------- | ------------------------------------------------------------ |\n| `@name` | Yes | Short human-readable name |\n| `@description` | Yes | Explanation of the query\'s purpose |\n| `@kind` | Yes | Output format: `problem`, `path-problem`, `table`, `graph` |\n| `@id` | Yes | Unique identifier (e.g., `js/sql-injection`) |\n| `@problem.severity` | For `problem`/`path-problem` | `error`, `warning`, or `recommendation` |\n| `@security-severity` | For security queries | CVSS score (e.g., `8.8`) |\n| `@precision` | Recommended | `very-high`, `high`, `medium`, or `low` |\n| `@tags` | Recommended | Categories like `security`, `correctness`, `maintainability` |\n\nUse `codeql_resolve_metadata` to extract and validate a query\'s metadata.\n\n## Common `@kind` Values\n\n- **`problem`** \u2014 Reports a single location with a message. Use `select element, message`.\n- **`path-problem`** \u2014 Reports a source-to-sink data flow path. Requires a `PathGraph` import and `select sink, source, sink, message`.\n- **`table`** \u2014 Generic tabular output (no alert interpretation).\n- **`graph`** \u2014 Structural output (AST, CFG, call graphs). Used by `PrintAST`, `PrintCFG`, `CallGraphFrom`, `CallGraphTo` tool queries.\n\n## Common QL Patterns\n\n### Predicate Definition\n\n```ql\npredicate isUserInput(DataFlow::Node node) {\n exists(Parameter p | p = node.asParameter() |\n p.getFunction().isPublic()\n )\n}\n```\n\n### Class Definition\n\n```ql\nclass DangerousCall extends MethodCall {\n DangerousCall() {\n this.getMethodName() = ["exec", "eval", "system"]\n }\n}\n```\n\n### Existential Quantifier (`exists`)\n\n```ql\nwhere exists(Assignment a | a.getLhs() = var and a.getRhs() instanceof NullLiteral)\n```\n\n### Aggregates\n\n```ql\nselect f, count(FunctionCall call | call.getTarget() = f) as callCount\n order by callCount desc\n```\n\n## Taint Tracking / Data Flow Configuration (v2 API)\n\n```ql\nmodule MyFlowConfig implements DataFlow::ConfigSig {\n predicate isSource(DataFlow::Node source) {\n // define sources\n }\n\n predicate isSink(DataFlow::Node sink) {\n // define sinks\n }\n\n predicate isBarrier(DataFlow::Node node) {\n // define sanitizers (optional)\n }\n}\n\nmodule MyFlow = TaintTracking::Global<MyFlowConfig>;\n```\n\n## Query Compilation and Validation\n\nUse these tools to validate queries at different fidelity levels:\n\n| Tool | Speed | Fidelity | When to Use |\n| ------------------------ | ------- | ------------------ | ----------------------------------------------------------------- |\n| `validate_codeql_query` | Instant | Heuristic only | Quick structure check (no compilation) |\n| `codeql_query_compile` | Fast | Full compilation | Syntax and type checking |\n| `codeql_lsp_diagnostics` | Fast | Full (single file) | Real-time validation during editing (cannot resolve pack imports) |\n\nTypical workflow:\n\n1. `validate_codeql_query` \u2014 quick structural check\n2. `codeql_query_compile` with `checkOnly: true` \u2014 full compilation\n3. `codeql_lsp_diagnostics` \u2014 interactive feedback during editing\n\n## Test File Conventions\n\nCodeQL query tests use this directory layout:\n\n```text\npack-root/\n\u251C\u2500\u2500 src/\n\u2502 \u251C\u2500\u2500 codeql-pack.yml # Source pack\n\u2502 \u2514\u2500\u2500 MyQuery/\n\u2502 \u2514\u2500\u2500 MyQuery.ql # The query\n\u2514\u2500\u2500 test/\n \u251C\u2500\u2500 codeql-pack.yml # Test pack\n \u2514\u2500\u2500 MyQuery/\n \u251C\u2500\u2500 MyQuery.qlref # Points to ../../src/MyQuery/MyQuery.ql\n \u251C\u2500\u2500 test.js # Test source code (language-appropriate)\n \u2514\u2500\u2500 MyQuery.expected # Expected query output\n```\n\n- **`.qlref` file**: Contains the relative path from the test pack\'s `src/` directory to the query file.\n- **`.expected` file**: Contains the expected output of running the query against the test code. Use `codeql_test_accept` to generate or update this file.\n- **Test source code**: Write code with both positive cases (should trigger the query) and negative cases (should not trigger).\n\n### Running Tests\n\n1. `codeql_test_run` \u2014 run tests and compare against `.expected` files\n2. `codeql_test_accept` \u2014 update `.expected` files when results are verified correct\n3. `codeql_resolve_tests` \u2014 discover and validate test structure\n\n## Related Resources\n\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://server/queries` \u2014 Bundled tools queries (PrintAST, PrintCFG, CallGraphFrom, CallGraphTo)\n- `codeql://server/tools` \u2014 Complete tool reference\n- `codeql://templates/security` \u2014 Security query templates\n- `codeql://learning/test-driven-development` \u2014 TDD workflow for CodeQL queries\n';
|
|
63045
63463
|
|
|
63046
63464
|
// src/resources/performance-patterns.md
|
|
63047
|
-
var performance_patterns_default = '# Performance Optimization Patterns\n\nThis resource describes how to evaluate and improve the performance of CodeQL queries using the MCP server\'s profiling tools. Rather than prescribing generic optimization rules, it focuses on using the `profile_codeql_query_from_logs` tool and the `explain_codeql_query` prompt to make evidence-based performance improvements.\n\n## Primary Performance Tool: `profile_codeql_query_from_logs`\n\nThe `profile_codeql_query_from_logs` tool is the primary means of evaluating the actual performance of a CodeQL query. It parses existing CodeQL evaluator logs into a structured performance profile without re-running the query.\n\n### Workflow\n\n1. **Run the query**: Use `codeql_query_run` with `evaluationOutput` set to a directory path. This generates evaluator log files.\n2. **
|
|
63465
|
+
var performance_patterns_default = '# Performance Optimization Patterns\n\nThis resource describes how to evaluate and improve the performance of CodeQL queries using the MCP server\'s profiling tools. Rather than prescribing generic optimization rules, it focuses on using the `profile_codeql_query_from_logs` tool and the `explain_codeql_query` prompt to make evidence-based performance improvements.\n\n## Primary Performance Tool: `profile_codeql_query_from_logs`\n\nThe `profile_codeql_query_from_logs` tool is the primary means of evaluating the actual performance of a CodeQL query. It parses existing CodeQL evaluator logs into a structured performance profile without re-running the query.\n\n### Workflow\n\n1. **Run the query**: Use `codeql_query_run` with `evaluationOutput` set to a directory path. This generates evaluator log files.\n2. **Profile**: Use `profile_codeql_query_from_logs` to parse the evaluator log. Returns compact JSON with the slowest predicates (by wall-clock time) and per-predicate metrics. Full RA operations and pipeline-stage tuple progressions are in a line-indexed detail file \u2014 use `read_file` with the `detailLines` ranges from the response to drill into any predicate.\n3. **Identify bottlenecks**: Review the profile JSON for predicates with high evaluation times, tuple count explosions in pipeline stages, or expensive RA operations (large JOINs, cross-products).\n4. **Refine**: Modify the query to address identified bottlenecks, then re-run and re-profile to verify improvements.\n\n### What the Profile Shows\n\n- **Predicate evaluation times** \u2014 which predicates are the most expensive\n- **Tuple counts** \u2014 how many intermediate results each predicate produces\n- **Pipeline stages** \u2014 the internal evaluation plan chosen by the CodeQL engine\n- **RA (relational algebra) operations** \u2014 join orders, aggregation steps, and recursive evaluations\n\n## Using `explain_codeql_query` for Performance Understanding\n\nThe `explain_codeql_query` prompt generates a detailed explanation of a query, including Mermaid evaluation diagrams that visualize the data flow and evaluation order. This is useful for understanding _why_ a query may be slow before profiling.\n\n## Key Performance Concepts\n\nThe following concepts are relevant when interpreting profiling output. Verify these against actual profiling data rather than applying them blindly.\n\n### Large Intermediate Result Sets\n\nWhen a predicate produces significantly more tuples than expected, it may indicate:\n\n- Missing or insufficiently restrictive filter conditions in the `where` clause\n- A cross-product between two large relations that should be joined more tightly\n\n**How to detect**: Look for predicates in the profile output with high tuple counts relative to their expected output size.\n\n### Recursive Predicate Costs\n\nRecursive predicates (e.g., transitive closures via `+` or `*`) can be expensive when the underlying relation is large. The profiler shows iteration counts and per-iteration tuple growth.\n\n**How to detect**: Look for recursive predicates with many iterations or high per-iteration costs in the profile output.\n\n### Join Order Sensitivity\n\nThe CodeQL evaluator chooses a join order for predicates in the `where` clause. In some cases, the chosen order may not be optimal.\n\n**How to detect**: Look for pipeline stages where a large intermediate result is produced before being filtered down. The profiler shows tuple counts at each stage.\n\n### Improving "Performance" \u2014 Two Dimensions\n\nThe word "performance" for CodeQL queries has two meanings:\n\n1. **Runtime efficiency** \u2014 how fast the query evaluates. Addressed by reducing tuple counts, improving join orders, and simplifying recursive predicates.\n2. **Result quality** \u2014 how accurate the query\'s output is (precision and recall). Addressed by refining source/sink/sanitizer definitions, adding or removing filter conditions, and testing against diverse codebases.\n\nThe `profile_codeql_query_from_logs` tool addresses runtime efficiency. For result quality, use the `run_query_and_summarize_false_positives` prompt and the `sarif_rank_false_positives` / `sarif_rank_true_positives` prompts.\n\n## Performance Review for GitHub Actions CodeQL Scans\n\nWhen reviewing CodeQL performance in the context of GitHub Actions CI/CD scans, key areas to examine include:\n\n### Code Exclusion\n\nExcluding non-essential files from analysis (vendored dependencies, generated code, test files) is one of the most impactful performance improvements. Any interpreted language or compiled language using `build-mode: none` can use a `paths-ignore` array in the CodeQL configuration file to exclude paths.\n\n### Hardware Sizing\n\nRecommended runner sizes based on lines of code:\n\n- Small (< 100K lines): 8 GB RAM, 2 cores\n- Medium (100K\u20131M lines): 16 GB RAM, 4\u20138 cores\n- Large (> 1M lines): 64 GB RAM, 8 cores\n\n### Monorepo Splitting\n\nFor monorepos with multiple independent applications separated by process/network boundaries, consider splitting CodeQL scans by application. This reduces database size and enables parallel scanning via Actions matrix strategies.\n\n## Related Tools and Prompts\n\n| Tool / Prompt | Purpose |\n| ------------------------------------------------ | -------------------------------------------------------- |\n| `profile_codeql_query_from_logs` | Profile from existing evaluator logs (primary tool) |\n| `codeql_generate_log-summary` | Optional: human-readable evaluator log summary |\n| `codeql_query_run` | Execute a query (set `evaluationOutput` to capture logs) |\n| `explain_codeql_query` prompt | Understand query evaluation flow with Mermaid diagrams |\n| `run_query_and_summarize_false_positives` prompt | Assess result quality (precision) |\n\n## Related Resources\n\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://learning/query-basics` \u2014 Query structure and compilation tools\n- `codeql://server/tools` \u2014 Complete tool reference\n- `codeql://learning/test-driven-development` \u2014 TDD workflow for iterative query improvement\n';
|
|
63048
63466
|
|
|
63049
63467
|
// src/resources/ql-test-driven-development.md
|
|
63050
63468
|
var ql_test_driven_development_default = "# Test-Driven Development for CodeQL Queries\n\nThis resource explains the theory and value of test-driven development (TDD) for CodeQL queries, and how the MCP server's tools and prompts support the TDD workflow. It is a conceptual overview \u2014 for step-by-step guided workflows, use the `test_driven_development`, `ql_tdd_basic`, or `ql_tdd_advanced` prompts.\n\n## Why TDD for CodeQL?\n\nCodeQL queries are programs that search for patterns in source code. Like any program, they can have bugs: false positives (flagging safe code), false negatives (missing vulnerable code), and runtime performance issues. TDD addresses all three by establishing a feedback loop between expected and actual behavior.\n\n### Why TDD Makes LLMs More Effective\n\nLLMs generating CodeQL queries face two challenges:\n\n1. **Syntactic correctness** \u2014 QL has unique syntax (classes, predicates, `exists`, aggregates) that differs from mainstream languages. Compilation via `codeql_query_compile` catches syntax errors early.\n2. **Semantic correctness** \u2014 A query that compiles may still produce wrong results. Test cases with `.expected` files provide ground truth that the LLM can compare against, enabling iterative refinement.\n\nTDD provides the LLM with a concrete, automated signal (tests pass / tests fail) at every iteration, replacing guesswork with evidence. This is especially valuable for data flow and taint tracking queries where the correctness of source/sink/sanitizer definitions can only be verified by running the query against representative code.\n\n## The TDD Cycle\n\n```text\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 1. Write Tests \u2502 \u2190 Define expected behavior through test cases\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u25BC\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 2. Run (Red) \u2502 \u2190 Verify tests fail (no query logic yet)\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u25BC\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 3. Implement \u2502 \u2190 Write minimal query logic to pass tests\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u25BC\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 4. Run (Green) \u2502 \u2190 Verify tests pass\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u25BC\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 5. Refactor \u2502 \u2190 Improve query while keeping tests green\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u25BC\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 6. Repeat \u2502 \u2190 Add more tests for additional scenarios\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n## The Value of AST Data in Test Code\n\nA critical step in the TDD workflow is running `PrintAST` on test source code before writing the query. The AST output reveals how the CodeQL database represents the test code \u2014 which QL classes correspond to which source constructs, and which predicates are available for matching.\n\nWithout AST data, the LLM must guess which classes and predicates to use, leading to trial-and-error. With AST data, the LLM can:\n\n- **Map source patterns to QL classes**: See exactly which QL class represents a `for` loop, a method call, or an assignment\n- **Discover available predicates**: Learn what methods are available on each AST node type\n- **Write precise `from`/`where` clauses**: Use the correct class names and predicate calls from the start\n\nUse `codeql_query_run` with `queryName=\"PrintAST\"` to generate AST data for test source files. The `ql_tdd_advanced` prompt guides this step in detail.\n\n## MCP Tools for TDD\n\n| Step | Tool | Purpose |\n| ------------ | ------------------------------------- | ---------------------------------------------------- |\n| Scaffold | `create_codeql_query` | Generate query, test, and `.qlref` files |\n| Dependencies | `codeql_pack_install` | Install pack dependencies for src and test packs |\n| Extract | `codeql_test_extract` | Create a test database from test source files |\n| AST Analysis | `codeql_query_run` (PrintAST) | Understand test code structure via AST |\n| CFG Analysis | `codeql_query_run` (PrintCFG) | Understand control flow (advanced) |\n| Call Graph | `codeql_query_run` (CallGraphFrom/To) | Trace call relationships (advanced) |\n| Compile | `codeql_query_compile` | Validate query syntax before testing |\n| Test | `codeql_test_run` | Run tests and compare against `.expected` |\n| Accept | `codeql_test_accept` | Update `.expected` when results are verified correct |\n| Profile | `profile_codeql_query_from_logs` | Analyze query performance from evaluator logs |\n| Format | `codeql_query_format` | Auto-format query source code |\n| Metadata | `codeql_resolve_metadata` | Validate query metadata annotations |\n\n## MCP Prompts for TDD\n\n| Prompt | When to Use |\n| ------------------------- | ---------------------------------------------------------- |\n| `test_driven_development` | End-to-end TDD workflow with required `language` parameter |\n| `ql_tdd_basic` | Standalone TDD checklist (all parameters optional) |\n| `ql_tdd_advanced` | Extended TDD with AST/CFG/call graph analysis |\n| `tools_query_workflow` | Focused exploration of code structure via tool queries |\n| `explain_codeql_query` | Understand an existing query's logic before modifying it |\n\n## Writing Effective Test Cases\n\n### Structure\n\nEach test directory contains:\n\n- **Test source code** (e.g., `test.js`) \u2014 code that the query will analyze\n- **`.qlref` file** \u2014 points to the query being tested\n- **`.expected` file** \u2014 the expected query output\n\n### Best Practices\n\n1. **Include both positive and negative cases**: Write code that should trigger the query (vulnerable patterns) and code that should not (safe patterns)\n2. **Start simple**: Begin with the most obvious positive and negative cases, then add edge cases\n3. **Use realistic code**: Test against code patterns that occur in real-world projects\n4. **One concept per test directory**: Each test should verify one specific behavior\n5. **Document intent**: Use comments in test code to explain why each case should or should not match\n\n### Example Test Structure\n\n```text\ntest/SqlInjection/\n\u251C\u2500\u2500 SqlInjection.qlref # Points to src/SqlInjection/SqlInjection.ql\n\u251C\u2500\u2500 test.py # Test source code\n\u2514\u2500\u2500 SqlInjection.expected # Expected results\n```\n\nThe `.expected` file contains one line per query result, matching the `select` clause output.\n\n## Related Resources\n\n- `codeql://server/overview` \u2014 MCP server orientation and quick-start guide\n- `codeql://learning/query-basics` \u2014 Query structure, metadata, and compilation reference\n- `codeql://server/tools` \u2014 Complete tool reference\n- `codeql://templates/security` \u2014 Security query templates with TDD workflow\n- `codeql://patterns/performance` \u2014 Performance profiling tools\n- `codeql://languages/{language}/ast` \u2014 Language-specific AST class reference\n- `codeql://languages/{language}/security` \u2014 Language-specific security patterns\n";
|
|
@@ -63065,7 +63483,7 @@ var server_prompts_default = "# MCP Server Prompts\n\nThis resource provides a c
|
|
|
63065
63483
|
var server_queries_default = '# MCP Server Bundled Queries\n\nThis resource describes the tools queries bundled with the CodeQL Development MCP Server. These queries run via `codeql_query_run` and provide structural insight into how source code is represented in a CodeQL database. Use them to understand code structure before writing detection queries.\n\nFor general QL query writing guidance (syntax, metadata, `from`/`where`/`select`, testing conventions), see `codeql://learning/query-basics`.\n\n## Bundled Tools Queries\n\nThe server bundles four tools queries that operate on CodeQL databases:\n\n| Query | Purpose | Output Format |\n| --------------- | ------------------------------------------------- | ------------------------- |\n| `PrintAST` | Visualize the Abstract Syntax Tree of source code | `@kind graph` (graphtext) |\n| `PrintCFG` | Visualize the Control Flow Graph of a function | `@kind graph` (graphtext) |\n| `CallGraphFrom` | Show all functions called FROM a given function | `@kind graph` (graphtext) |\n| `CallGraphTo` | Show all call sites that call TO a given function | `@kind graph` (graphtext) |\n\nAll four queries use `@kind graph` metadata and produce output in graphtext format.\n\n## PrintAST\n\n**Purpose**: Outputs a hierarchical representation of the Abstract Syntax Tree showing parent-child relationships between declarations, statements, and expressions.\n\n**When to use**: Before writing any CodeQL query, run `PrintAST` on your test source code to understand which QL classes represent which source constructs and which predicates are available for matching.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "PrintAST"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFiles: "<comma-separated-filenames>" (optional \u2014 filter to specific files)\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A tree showing each AST node with its QL class name, properties, and position in the hierarchy. This reveals exactly which QL classes and predicates to use in `from`/`where`/`select` clauses.\n\n## PrintCFG\n\n**Purpose**: Produces a Control Flow Graph representation showing the order in which statements and expressions execute, including branching paths.\n\n**When to use**: When writing queries that reason about execution order, reachability, or branching logic (e.g., "is this check always performed before this call?").\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "PrintCFG"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFunction: "<function-name>" (optional \u2014 target a specific function)\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: Nodes representing CFG basic blocks and edges representing possible execution transitions (successor relationships).\n\n## CallGraphFrom\n\n**Purpose**: Shows all functions called FROM a specified source function \u2014 the outbound call dependencies.\n\n**When to use**: When analyzing what a function does by tracing the functions it invokes. Useful for understanding call chains and identifying potential data flow paths.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "CallGraphFrom"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFunction: "<function-name>"\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A graph showing each call site within the source function and the target function being called.\n\n## CallGraphTo\n\n**Purpose**: Shows all call sites that invoke a specified target function \u2014 the inbound callers.\n\n**When to use**: When performing impact analysis to understand where a function is used, or when identifying all locations that pass data to a particular sink function.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "CallGraphTo"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n targetFunction: "<function-name>"\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A graph showing each caller function and the specific call site where the target function is invoked.\n\n## Language Support\n\n| Language | PrintAST | PrintCFG | CallGraphFrom | CallGraphTo |\n| ---------- | :------: | :------: | :-----------: | :---------: |\n| actions | \u2713 | \u2713 | | |\n| cpp | \u2713 | \u2713 | \u2713 | \u2713 |\n| csharp | \u2713 | \u2713 | \u2713 | \u2713 |\n| go | \u2713 | \u2713 | \u2713 | \u2713 |\n| java | \u2713 | \u2713 | \u2713 | \u2713 |\n| javascript | \u2713 | \u2713 | \u2713 | \u2713 |\n| python | \u2713 | \u2713 | \u2713 | \u2713 |\n| ruby | \u2713 | \u2713 | \u2713 | \u2713 |\n| swift | \u2713 | \u2713 | \u2713 | \u2713 |\n\nNote: The `actions` language supports PrintAST and PrintCFG only (no call graph queries).\n\n## Recommended Workflow\n\nUse the `tools_query_workflow` prompt for a guided step-by-step workflow:\n\n1. **Identify or create a database**: Use `list_codeql_databases` or `codeql_database_create`\n2. **Run PrintAST**: Understand how the source code maps to QL classes\n3. **Run PrintCFG**: Understand control flow for the functions of interest\n4. **Run CallGraphFrom / CallGraphTo**: Trace call relationships to identify sources and sinks\n5. **Write detection queries**: Use the insights from steps 2\u20134 to select the right QL classes and predicates\n\n## Related Resources\n\n- `codeql://learning/query-basics` \u2014 QL query writing reference (syntax, metadata, patterns, testing)\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://server/tools` \u2014 Complete tool reference\n- `codeql://learning/test-driven-development` \u2014 TDD workflow for CodeQL queries\n- `codeql://languages/{language}/ast` \u2014 Language-specific AST class reference\n';
|
|
63066
63484
|
|
|
63067
63485
|
// src/resources/server-tools.md
|
|
63068
|
-
var server_tools_default = '# MCP Server Tools\n\nThis resource provides a complete reference of the default tools exposed by the CodeQL Development MCP Server. These tools wrap the CodeQL CLI and supporting utilities, enabling an LLM to develop, test, and analyze CodeQL queries programmatically.\n\n## CodeQL CLI Tools\n\n| Tool | Description |\n| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_bqrs_decode` | Decode BQRS result files to human-readable formats (text, csv, json). Supports `--result-set` and `--rows` for pagination |\n| `codeql_bqrs_info` | Get metadata about BQRS result files: result sets, column types, row counts |\n| `codeql_bqrs_interpret` | Interpret BQRS result files according to query metadata and generate output in specified formats (CSV, SARIF, graph formats) |\n| `codeql_database_analyze` | Run queries or query suites against CodeQL databases. Produces evaluator logs, BQRS, and SARIF output |\n| `codeql_database_create` | Create a CodeQL database from source code |\n| `codeql_generate_log-summary` | Create a summary of a structured JSON evaluator event log file |\n| `codeql_generate_query-help` | Generate query help documentation from QLDoc comments |\n| `codeql_pack_install` | Install CodeQL pack dependencies |\n| `codeql_pack_ls` | List CodeQL packs under a local directory path |\n| `codeql_query_compile` | Compile and validate CodeQL queries |\n| `codeql_query_format` | Automatically format CodeQL source code files |\n| `codeql_query_run` | Execute a CodeQL query against a database |\n| `codeql_resolve_database` | Resolve database path and validate database structure |\n| `codeql_resolve_languages` | List installed CodeQL extractor packs |\n| `codeql_resolve_library-path` | Resolve library path for CodeQL queries and libraries |\n| `codeql_resolve_metadata` | Resolve and return key-value metadata pairs from a CodeQL query source file |\n| `codeql_resolve_qlref` | Resolve `.qlref` files to their corresponding query files |\n| `codeql_resolve_queries` | List available CodeQL queries found on the local filesystem |\n| `codeql_resolve_tests` | Resolve the local filesystem paths of unit tests and/or queries under a base directory |\n| `codeql_test_accept` | Accept new test results as the expected baseline |\n| `codeql_test_extract` | Extract test databases for CodeQL query tests |\n| `codeql_test_run` | Run CodeQL query tests |\n\n## Language Server Protocol (LSP) Tools\n\n| Tool | Description |\n| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_lsp_completion` | Get code completions at a cursor position in a CodeQL file |\n| `codeql_lsp_definition` | Go to the definition of a CodeQL symbol at a given position |\n| `codeql_lsp_diagnostics` | Syntax and semantic validation of CodeQL code via the Language Server. Note: inline `ql_code` cannot resolve pack imports; use `codeql_query_compile` for files with imports |\n| `codeql_lsp_references` | Find all references to a CodeQL symbol at a given position |\n\n## Query Development Tools\n\n| Tool | Description |\n| -------------------------------- | ------------------------------------------------------------------------------------------------------------ |\n| `create_codeql_query` | Create directory structure and files for a new CodeQL query with tests |\n| `find_class_position` | Find the start/end line and column of a class for quick evaluation |\n| `find_codeql_query_files` | Find and track all files and directories related to a CodeQL query, including resolved metadata |\n| `find_predicate_position` | Find the start/end line and column of a predicate for quick evaluation |\n| `list_codeql_databases` | List CodeQL databases discovered in configured base directories |\n| `list_mrva_run_results` | List MRVA (Multi-Repository Variant Analysis) run results with per-repo details |\n| `list_query_run_results` | List query run result directories with artifact inventory. Filter by `queryName`, `language`, or `queryPath` |\n| `profile_codeql_query` | Profile the performance of a CodeQL query run against a specific database by analyzing the evaluator log |\n| `profile_codeql_query_from_logs` | Parse existing CodeQL evaluator logs into a performance profile without re-running the query |\n| `quick_evaluate` | Quick evaluate either a class or a predicate in a CodeQL query for debugging |\n| `read_database_source` | Read source file contents from a CodeQL database source archive. Omit `filePath` to list all files |\n| `register_database` | Register a CodeQL database given a local path to the database directory |\n| `validate_codeql_query` | Quick heuristic validation for CodeQL query structure (does not compile the query) |\n\n## Common Tool Workflows\n\n### Create and Test a Query\n\n1. `create_codeql_query` \u2014 scaffold files\n2. `codeql_pack_install` \u2014 install dependencies\n3. `codeql_query_compile` \u2014 validate syntax\n4. `codeql_test_run` \u2014 run tests\n5. `codeql_test_accept` \u2014 accept correct results\n\n### Understand Code Structure\n\n1. `codeql_query_run` with `queryName="PrintAST"` \u2014 visualize the AST\n2. `codeql_query_run` with `queryName="PrintCFG"` \u2014 visualize control flow\n3. `codeql_query_run` with `queryName="CallGraphFrom"` / `"CallGraphTo"` \u2014 trace call relationships\n\n### Profile Query Performance\n\n1. `codeql_query_run` with `evaluationOutput` \u2014 run query and capture evaluator logs\n2. `profile_codeql_query_from_logs` \u2014 analyze evaluator logs for bottlenecks\n3. `codeql_generate_log-summary` \u2014 generate a human-readable log summary\n\n### Interactive Development\n\n1. `codeql_lsp_completion` \u2014 get QL code completions\n2. `codeql_lsp_definition` \u2014 navigate to definitions\n3. `codeql_lsp_references` \u2014 find all references\n4. `codeql_lsp_diagnostics` \u2014 real-time validation\n\n## Tool Input Conventions\n\n- **LSP tools** use **0-based** line and column positions for input. Output uses 1-based `startLine`/`endLine`.\n- **`find_predicate_position`** and **`find_class_position`** return **1-based** positions.\n- **`workspace_uri`** for LSP tools must be a **plain directory path** to the pack root containing `codeql-pack.yml`, not a `file://` URI.\n\n## Related Resources\n\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://server/prompts` \u2014 Complete prompt reference\n- `codeql://learning/query-basics` \u2014 Query writing reference\n- `codeql://patterns/performance` \u2014 Performance profiling guide\n';
|
|
63486
|
+
var server_tools_default = '# MCP Server Tools\n\nThis resource provides a complete reference of the default tools exposed by the CodeQL Development MCP Server. These tools wrap the CodeQL CLI and supporting utilities, enabling an LLM to develop, test, and analyze CodeQL queries programmatically.\n\n## CodeQL CLI Tools\n\n| Tool | Description |\n| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_bqrs_decode` | Decode BQRS result files to human-readable formats (text, csv, json). Supports `--result-set` and `--rows` for pagination |\n| `codeql_bqrs_info` | Get metadata about BQRS result files: result sets, column types, row counts |\n| `codeql_bqrs_interpret` | Interpret BQRS result files according to query metadata and generate output in specified formats (CSV, SARIF, graph formats) |\n| `codeql_database_analyze` | Run queries or query suites against CodeQL databases. Produces evaluator logs, BQRS, and SARIF output |\n| `codeql_database_create` | Create a CodeQL database from source code |\n| `codeql_generate_log-summary` | Create a summary of a structured JSON evaluator event log file |\n| `codeql_generate_query-help` | Generate query help documentation from QLDoc comments |\n| `codeql_pack_install` | Install CodeQL pack dependencies |\n| `codeql_pack_ls` | List CodeQL packs under a local directory path |\n| `codeql_query_compile` | Compile and validate CodeQL queries |\n| `codeql_query_format` | Automatically format CodeQL source code files |\n| `codeql_query_run` | Execute a CodeQL query against a database |\n| `codeql_resolve_database` | Resolve database path and validate database structure |\n| `codeql_resolve_files` | Find files in a directory tree, filtered by extension and glob patterns. Useful for discovering QL library files |\n| `codeql_resolve_languages` | List installed CodeQL extractor packs |\n| `codeql_resolve_library-path` | Resolve library path for CodeQL queries and libraries |\n| `codeql_resolve_metadata` | Resolve and return key-value metadata pairs from a CodeQL query source file |\n| `codeql_resolve_qlref` | Resolve `.qlref` files to their corresponding query files |\n| `codeql_resolve_queries` | List available CodeQL queries found on the local filesystem |\n| `codeql_resolve_tests` | Resolve the local filesystem paths of unit tests and/or queries under a base directory |\n| `codeql_test_accept` | Accept new test results as the expected baseline |\n| `codeql_test_extract` | Extract test databases for CodeQL query tests |\n| `codeql_test_run` | Run CodeQL query tests |\n\n## Language Server Protocol (LSP) Tools\n\n| Tool | Description |\n| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_lsp_completion` | Get code completions at a cursor position in a CodeQL file |\n| `codeql_lsp_definition` | Go to the definition of a CodeQL symbol at a given position |\n| `codeql_lsp_diagnostics` | Syntax and semantic validation of CodeQL code via the Language Server. Note: inline `ql_code` cannot resolve pack imports; use `codeql_query_compile` for files with imports |\n| `codeql_lsp_references` | Find all references to a CodeQL symbol at a given position |\n\n## Query Development Tools\n\n| Tool | Description |\n| -------------------------------- | ------------------------------------------------------------------------------------------------------------ |\n| `create_codeql_query` | Create directory structure and files for a new CodeQL query with tests |\n| `find_class_position` | Find the start/end line and column of a class for quick evaluation |\n| `find_codeql_query_files` | Find and track all files and directories related to a CodeQL query, including resolved metadata |\n| `find_predicate_position` | Find the start/end line and column of a predicate for quick evaluation |\n| `list_codeql_databases` | List CodeQL databases discovered in configured base directories |\n| `list_mrva_run_results` | List MRVA (Multi-Repository Variant Analysis) run results with per-repo details |\n| `list_query_run_results` | List query run result directories with artifact inventory. Filter by `queryName`, `language`, or `queryPath` |\n| `profile_codeql_query` | Profile the performance of a CodeQL query run against a specific database by analyzing the evaluator log |\n| `profile_codeql_query_from_logs` | Parse evaluator logs into a compact profile with line-indexed detail file for targeted read_file access |\n| `quick_evaluate` | Quick evaluate either a class or a predicate in a CodeQL query for debugging |\n| `read_database_source` | Read source file contents from a CodeQL database source archive. Omit `filePath` to list all files |\n| `register_database` | Register a CodeQL database given a local path to the database directory |\n| `search_ql_code` | Search QL source files for text or regex patterns with structured results (replaces grep for QL code) |\n| `validate_codeql_query` | Quick heuristic validation for CodeQL query structure (does not compile the query) |\n\n## Common Tool Workflows\n\n### Create and Test a Query\n\n1. `create_codeql_query` \u2014 scaffold files\n2. `codeql_pack_install` \u2014 install dependencies\n3. `codeql_query_compile` \u2014 validate syntax\n4. `codeql_test_run` \u2014 run tests\n5. `codeql_test_accept` \u2014 accept correct results\n\n### Understand Code Structure\n\n1. `codeql_query_run` with `queryName="PrintAST"` \u2014 visualize the AST\n2. `codeql_query_run` with `queryName="PrintCFG"` \u2014 visualize control flow\n3. `codeql_query_run` with `queryName="CallGraphFrom"` / `"CallGraphTo"` \u2014 trace call relationships\n\n### Profile Query Performance\n\n1. `codeql_query_run` with `evaluationOutput` \u2014 run query and capture evaluator logs\n2. `profile_codeql_query_from_logs` \u2014 analyze evaluator logs: slowest predicates, RA operations, tuple count progressions, dependencies\n\n### Discover and Search QL Code\n\n1. `codeql_resolve_files` \u2014 find QL files by extension and glob patterns in library packs\n2. `search_ql_code` \u2014 search QL source files for classes, predicates, or patterns by text/regex\n3. `codeql_lsp_definition` \u2014 navigate to the definition of a discovered symbol\n4. `codeql_lsp_references` \u2014 find all usages of a symbol across a pack\n\n### Interactive Development\n\n1. `codeql_lsp_completion` \u2014 get QL code completions\n2. `codeql_lsp_definition` \u2014 navigate to definitions\n3. `codeql_lsp_references` \u2014 find all references\n4. `codeql_lsp_diagnostics` \u2014 real-time validation\n\n## Tool Input Conventions\n\n- **LSP tools** use **0-based** line and column positions for input. Output uses 1-based `startLine`/`endLine`.\n- **`find_predicate_position`** and **`find_class_position`** return **1-based** positions.\n- **`workspace_uri`** for LSP tools must be a **plain directory path** to the pack root containing `codeql-pack.yml`, not a `file://` URI.\n\n## Related Resources\n\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://server/prompts` \u2014 Complete prompt reference\n- `codeql://learning/query-basics` \u2014 Query writing reference\n- `codeql://patterns/performance` \u2014 Performance profiling guide\n';
|
|
63069
63487
|
|
|
63070
63488
|
// src/lib/resources.ts
|
|
63071
63489
|
function getLearningQueryBasics() {
|
|
@@ -63296,13 +63714,13 @@ function registerCodeQLResources(server) {
|
|
|
63296
63714
|
// src/tools/lsp/lsp-diagnostics.ts
|
|
63297
63715
|
init_logger();
|
|
63298
63716
|
init_temp_dir();
|
|
63299
|
-
import { join as
|
|
63717
|
+
import { join as join17 } from "path";
|
|
63300
63718
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
63301
63719
|
|
|
63302
63720
|
// src/tools/lsp/lsp-server-helper.ts
|
|
63303
63721
|
init_server_manager();
|
|
63304
63722
|
init_logger();
|
|
63305
|
-
import { isAbsolute as isAbsolute5, resolve as
|
|
63723
|
+
import { isAbsolute as isAbsolute5, resolve as resolve11 } from "path";
|
|
63306
63724
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
63307
63725
|
async function getInitializedLanguageServer(opts = {}) {
|
|
63308
63726
|
const { packageRootDir: pkgRoot, getUserWorkspaceDir: getUserWorkspaceDir2 } = await Promise.resolve().then(() => (init_package_paths(), package_paths_exports));
|
|
@@ -63310,7 +63728,7 @@ async function getInitializedLanguageServer(opts = {}) {
|
|
|
63310
63728
|
const config2 = {
|
|
63311
63729
|
checkErrors: "ON_CHANGE",
|
|
63312
63730
|
loglevel: options.loglevel ?? "WARN",
|
|
63313
|
-
searchPath: options.searchPath ??
|
|
63731
|
+
searchPath: options.searchPath ?? resolve11(pkgRoot, "ql"),
|
|
63314
63732
|
synchronous: options.synchronous,
|
|
63315
63733
|
verbosity: options.verbosity
|
|
63316
63734
|
};
|
|
@@ -63318,10 +63736,10 @@ async function getInitializedLanguageServer(opts = {}) {
|
|
|
63318
63736
|
const server = await manager.getLanguageServer(config2);
|
|
63319
63737
|
let effectiveUri = opts.workspaceUri;
|
|
63320
63738
|
if (effectiveUri && !effectiveUri.startsWith("file://")) {
|
|
63321
|
-
const absWorkspace = isAbsolute5(effectiveUri) ? effectiveUri :
|
|
63739
|
+
const absWorkspace = isAbsolute5(effectiveUri) ? effectiveUri : resolve11(getUserWorkspaceDir2(), effectiveUri);
|
|
63322
63740
|
effectiveUri = pathToFileURL2(absWorkspace).href;
|
|
63323
63741
|
}
|
|
63324
|
-
effectiveUri = effectiveUri ?? pathToFileURL2(
|
|
63742
|
+
effectiveUri = effectiveUri ?? pathToFileURL2(resolve11(pkgRoot, "ql")).href;
|
|
63325
63743
|
await server.initialize(effectiveUri);
|
|
63326
63744
|
logger.debug(`Language server initialized with workspace: ${effectiveUri}`);
|
|
63327
63745
|
return server;
|
|
@@ -63394,7 +63812,7 @@ async function lspDiagnostics({
|
|
|
63394
63812
|
serverOptions,
|
|
63395
63813
|
workspaceUri
|
|
63396
63814
|
});
|
|
63397
|
-
const evalUri = pathToFileURL3(
|
|
63815
|
+
const evalUri = pathToFileURL3(join17(getProjectTmpDir("lsp-eval"), `eval_${Date.now()}.ql`)).href;
|
|
63398
63816
|
const diagnostics = await languageServer.evaluateQL(qlCode, evalUri);
|
|
63399
63817
|
const summary = {
|
|
63400
63818
|
errorCount: diagnostics.filter((d) => d.severity === 1).length,
|
|
@@ -63483,7 +63901,7 @@ function registerLspDiagnosticsTool(server) {
|
|
|
63483
63901
|
init_logger();
|
|
63484
63902
|
init_package_paths();
|
|
63485
63903
|
import { readFile as readFile3 } from "fs/promises";
|
|
63486
|
-
import { isAbsolute as isAbsolute6, resolve as
|
|
63904
|
+
import { isAbsolute as isAbsolute6, resolve as resolve12 } from "path";
|
|
63487
63905
|
import { pathToFileURL as pathToFileURL4 } from "url";
|
|
63488
63906
|
async function getInitializedServer(params) {
|
|
63489
63907
|
return getInitializedLanguageServer({
|
|
@@ -63492,7 +63910,7 @@ async function getInitializedServer(params) {
|
|
|
63492
63910
|
});
|
|
63493
63911
|
}
|
|
63494
63912
|
function prepareDocumentPosition(params) {
|
|
63495
|
-
const absPath = isAbsolute6(params.filePath) ? params.filePath :
|
|
63913
|
+
const absPath = isAbsolute6(params.filePath) ? params.filePath : resolve12(getUserWorkspaceDir(), params.filePath);
|
|
63496
63914
|
const docUri = pathToFileURL4(absPath).href;
|
|
63497
63915
|
return { absPath, docUri };
|
|
63498
63916
|
}
|
|
@@ -63839,22 +64257,22 @@ function registerLanguageResources(server) {
|
|
|
63839
64257
|
}
|
|
63840
64258
|
|
|
63841
64259
|
// src/prompts/workflow-prompts.ts
|
|
63842
|
-
import { basename as
|
|
64260
|
+
import { basename as basename7 } from "path";
|
|
63843
64261
|
|
|
63844
64262
|
// src/prompts/document-codeql-query.prompt.md
|
|
63845
64263
|
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';
|
|
63846
64264
|
|
|
63847
64265
|
// src/prompts/explain-codeql-query.prompt.md
|
|
63848
|
-
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.
|
|
64266
|
+
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';
|
|
63849
64267
|
|
|
63850
64268
|
// src/prompts/ql-lsp-iterative-development.prompt.md
|
|
63851
|
-
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\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 grep 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';
|
|
64269
|
+
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';
|
|
63852
64270
|
|
|
63853
64271
|
// src/prompts/ql-tdd-advanced.prompt.md
|
|
63854
|
-
var ql_tdd_advanced_prompt_default = '---\nagent: agent\n---\n\n# Advanced Test-Driven CodeQL Query Development\n\nThis advanced guide builds on the basic TDD methodology with powerful MCP server tools for deeper code analysis. Use this when developing complex queries that require understanding AST structure, control flow, and call relationships.\n\nFor basic TDD workflow, see: `codeql://prompts/ql-tdd-basic`\n\n## When to Use This Advanced Guide\n\n- **Complex AST patterns**: When you need to understand how CodeQL represents specific language constructs\n- **Control flow queries**: When analyzing program flow, branching, or loop structures\n- **Call graph analysis**: When tracing function calls or method invocations\n- **Iterative refinement**: When debugging queries that don\'t produce expected results\n- **Performance optimization**: When understanding query evaluation patterns\n\n## Core Advanced Tools\n\n### 1. AST/CFG Visualization with #codeql_query_run\n\nUse the bundled tools queries to visualize code structure:\n\n```typescript\n// Generate Abstract Syntax Tree for test code\ncodeql_query_run: {\n queryName: "PrintAST",\n queryLanguage: "java", // or "javascript", "python", "cpp", etc.\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/ast-output.txt"\n}\n\n// Generate Control Flow Graph\ncodeql_query_run: {\n queryName: "PrintCFG",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/cfg-output.txt"\n}\n\n// Analyze outbound calls from a function\ncodeql_query_run: {\n queryName: "CallGraphFrom",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n sourceFunction: "myFunction",\n format: "sarif-latest"\n}\n\n// Analyze inbound calls to a function\ncodeql_query_run: {\n queryName: "CallGraphTo",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n targetFunction: "targetMethod",\n format: "sarif-latest"\n}\n```\n\n**Critical**: Always verify that tools queries return **non-empty output** with actual nodes/edges, not just headers.\n\n### 2. Quick Evaluation with #quick_evaluate\n\nUse #quick_evaluate for rapid iteration on specific predicates or classes:\n\n```typescript\n// First, find the position of a predicate\nfind_predicate_position: {\n file: "/path/to/Query.ql",\n name: "isVulnerableSink"\n}\n\n// Then evaluate just that predicate\nquick_evaluate: {\n file: "/path/to/Query.ql",\n db: "/path/to/test.testproj",\n symbol: "isVulnerableSink",\n output_path: "/tmp/quickeval.bqrs"\n}\n\n// Or evaluate a specific class\n// NOTE: find_class_position finds `class` definitions only, not `module` definitions\nfind_class_position: {\n file: "/path/to/Query.ql",\n name: "ThrowingMethodCall"\n}\n\nquick_evaluate: {\n file: "/path/to/Query.ql",\n db: "/path/to/test.testproj",\n symbol: "ThrowingMethodCall"\n}\n```\n\n### 3. LSP-Powered Code Navigation\n\nUse the LSP tools for real-time code exploration during query development:\n\n```typescript\n// Discover available types after `import javascript`\ncodeql_lsp_completion: {\n file_path: "/path/to/Query.ql",\n line: 5, // 0-based line with `from` clause\n character: 5, // 0-based column position\n workspace_uri: "/path/to/pack-root" // REQUIRED: directory containing codeql-pack.yml\n}\n\n// Navigate to a class definition to see its predicates\ncodeql_lsp_definition: {\n file_path: "/path/to/Query.ql",\n line: 5, // 0-based line containing the class name\n character: 10, // 0-based column on the class name\n workspace_uri: "/path/to/pack-root"\n}\n\n// Find all usages of a predicate across the pack\ncodeql_lsp_references: {\n file_path: "/path/to/Query.ql",\n line: 8,\n character: 5,\n workspace_uri: "/path/to/pack-root"\n}\n```\n\n**Important LSP tool notes**:\n\n- `workspace_uri` must be a **plain directory path** (not a `file://` URI) pointing to the pack root containing `codeql-pack.yml`\n- All LSP tools use **0-based** line/character positions\n- #find_predicate_position and #find_class_position return **1-based** positions \u2014 subtract 1 before passing to LSP tools\n- Run #codeql_pack_install before using LSP tools \u2014 they require resolved dependencies\n- Request completions **after a dot** (e.g., `pw.`) to see all member predicates with full documentation\n\n### 4. Query File Discovery with #find_codeql_query_files\n\nUse this tool frequently to understand query dependencies and test structure:\n\n```typescript\nfind_codeql_query_files: {\n queryPath: \'/path/to/Query.ql\';\n}\n// Returns: query file, test directory, test files, metadata, dependencies\n```\n\n## Advanced TDD Workflow\n\n### Phase 0: Test Environment Setup (Critical for Java)\n\nFor Java tests that depend on external libraries (JUnit, etc.), create an `options` file in each test directory:\n\n```text\n//semmle-extractor-options: --javac-args -cp ${testdir}/../../stubs/junit-4.13:${testdir}/../../stubs/junit-jupiter-api-5.2.0\n```\n\n**Key points**:\n\n- `${testdir}` is relative to the test directory containing the `options` file\n- Use `:` (colon) to separate multiple classpath entries\n- Stub files must contain minimal class/interface definitions for compilation\n\n### Phase 1: Deep Code Analysis\n\nBefore writing any query logic:\n\n1. **Extract test database**:\n\n ```typescript\n codeql_test_extract: {\n testPath: "/path/to/test/QueryTest",\n searchPath: "/path/to/pack"\n }\n ```\n\n2. **Generate and study the AST**:\n\n ```typescript\n codeql_query_run: {\n queryName: "PrintAST",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/ast.txt"\n }\n ```\n\n3. **Identify key AST classes and predicates** from the output:\n - Note the class names (e.g., `MethodCall`, `TryStmt`, `LambdaExpr`)\n - Note parent-child relationships\n - Identify which nodes correspond to your test cases\n\n4. **Generate CFG if analyzing control flow**:\n\n ```typescript\n codeql_query_run: {\n queryName: "PrintCFG",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/cfg.txt"\n }\n ```\n\n### Phase 2: Iterative Predicate Development\n\nInstead of writing the full query at once:\n\n1. **Start with a single class or predicate**:\n\n ```ql\n class MyPattern extends MethodCall {\n MyPattern() {\n this.getMethod().hasName("targetMethod")\n }\n }\n ```\n\n2. **Use #quick_evaluate to test it**:\n\n ```typescript\n quick_evaluate: {\n file: "/path/to/Query.ql",\n db: "/path/to/test.testproj",\n symbol: "MyPattern"\n }\n ```\n\n3. **Refine based on results**:\n - Too many results? Add constraints\n - Too few results? Relax constraints\n - Wrong results? Study AST output again\n\n4. **Repeat for each component** before combining\n\n### Phase 3: Incremental Query Assembly\n\n1. **Combine validated predicates** into the main query\n2. **Run full tests** after each combination:\n\n ```typescript\n codeql_test_run: {\n testPath: "/path/to/test/QueryTest",\n searchPath: "/path/to/pack"\n }\n ```\n\n3. **Use #find_codeql_query_files** to track all related files:\n\n ```typescript\n find_codeql_query_files: {\n queryPath: \'/path/to/Query.ql\';\n }\n ```\n\n## Common Advanced Patterns\n\n### Pattern: Understanding Nested Structures\n\nWhen your query involves nested constructs (e.g., lambdas inside method calls):\n\n```ql\n// First, find the outer construct\nclass OuterPattern extends MethodCall {\n OuterPattern() {\n this.getMethod().hasName("assertThrows")\n }\n\n // Navigate to inner construct\n Expr getLambdaBody() {\n exists(LambdaExpr le |\n le = this.getAChildExpr() and\n result = le.getExprBody()\n )\n }\n}\n```\n\nUse `PrintAST` to understand the parent-child relationships.\n\n### Pattern: Control Flow Dependencies\n\nWhen your query needs to understand execution order:\n\n```ql\n// Use CFG to understand which statements precede others\npredicate precedesInBlock(Stmt s1, Stmt s2) {\n exists(BasicBlock bb |\n s1.getBasicBlock() = bb and\n s2.getBasicBlock() = bb and\n s1.getLocation().getStartLine() < s2.getLocation().getStartLine()\n )\n}\n```\n\nUse `PrintCFG` to verify the control flow structure.\n\n### Pattern: Call Chain Analysis\n\nWhen tracing calls through multiple functions:\n\n```typescript\n// First, understand the call graph from your entry point\ncodeql_query_run: {\n queryName: "CallGraphFrom",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n sourceFunction: "entryPoint"\n}\n\n// Then trace back from your target\ncodeql_query_run: {\n queryName: "CallGraphTo",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n targetFunction: "sensitiveOperation"\n}\n```\n\n## Debugging Tips\n\n### When Results Are Empty\n\n1. **Check AST first**: Run `PrintAST` to verify the code structure matches expectations\n2. **Simplify the query**: Remove constraints one by one using #quick_evaluate\n3. **Check enclosing callables**: Lambda bodies may have different `getEnclosingCallable()` than expected\n4. **Verify test database extraction**: Ensure the `.testproj` directory was created successfully\n\n### When Results Are Incorrect\n\n1. **Quick evaluate individual predicates**: Isolate which part is wrong\n2. **Compare with AST output**: Verify your understanding of the structure\n3. **Check for missing cases**: Your pattern may not cover all code variations\n\n### When Compilation Fails with "override" Error\n\nIf you see `annotation \'override\' missing on predicate`, you\'ve accidentally created a predicate with the same name as one in the parent class. **Rename your predicate** to avoid the conflict:\n\n```ql\n// BAD: Method already has getAThrownExceptionType()\nclass ThrowingMethod extends Method {\n RefType getAThrownExceptionType() { ... } // Error!\n}\n\n// GOOD: Use a distinct name\nclass ThrowingMethod extends Method {\n RefType getDeclaredExceptionType() { ... } // Works\n}\n```\n\n### When Query Is Slow\n\n1. **Enable evaluator logs**:\n\n ```typescript\n codeql_query_run: {\n query: "/path/to/Query.ql",\n database: "/path/to/db",\n "evaluator-log": "/path/to/log.json",\n "evaluator-log-level": 5\n }\n ```\n\n2. **Generate log summary**:\n\n ```typescript\n codeql_generate_log_summary: {\n inputLog: "/path/to/log.json",\n format: "text"\n }\n ```\n\n3. **Profile from evaluator logs** (after step 1 produces a log file):\n\n ```typescript\n profile_codeql_query_from_logs: {\n evaluatorLog: \'/path/to/log.json\';\n }\n ```\n\n## Checklist for Complex Queries\n\n### Before Starting\n\n- [ ] Test database extracted successfully\n- [ ] `PrintAST` output reviewed and understood\n- [ ] Key AST classes identified\n- [ ] Test cases cover positive, negative, and edge cases\n\n### During Development\n\n- [ ] Each predicate/class tested with #quick_evaluate\n- [ ] #find_codeql_query_files used to track dependencies\n- [ ] CFG consulted for control flow patterns\n- [ ] Call graphs generated for cross-function analysis\n\n### After Each Change\n\n- [ ] Query compiles with #codeql_query_compile\n- [ ] Quick evaluation shows expected results\n- [ ] Full tests pass with #codeql_test_run\n- [ ] No duplicate or missing results\n\n### Final Validation\n\n- [ ] All test cases pass\n- [ ] No false positives in results\n- [ ] No false negatives (all expected cases caught)\n- [ ] Query formatted with #codeql_query_format\n- [ ] Performance acceptable (check with #profile_codeql_query_from_logs)\n\n## Test Acceptance Workflow\n\nWhen your query produces correct results but differs from the `.expected` file:\n\n1. **Review the `.actual` file** to verify results are correct\n2. **Accept the results** to update the expected baseline:\n\n ```typescript\n codeql_test_accept: {\n tests: [\'/path/to/test/QueryTest\'];\n }\n ```\n\n3. **Re-run tests** to confirm they now pass\n\n**Warning**: Only accept results after careful review. Don\'t blindly accept to make tests pass.\n\n## Tool Reference\n\n| Tool | Purpose | When to Use |\n| ------------------------------- | --------------------------------- | ------------------------------- |\n| #codeql_query_run (PrintAST) | Visualize AST structure | Start of development, debugging |\n| #codeql_query_run (PrintCFG) | Visualize control flow | Control flow queries |\n| #codeql_query_run (CallGraph\\*) | Analyze call relationships | Cross-function queries |\n| #codeql_bqrs_interpret | Convert BQRS to readable format | After running graph queries |\n| #quick_evaluate | Test individual predicates | Iterative development |\n| #find_predicate_position | Locate predicate for quickeval | Before quick_evaluate |\n| #find_class_position | Locate class for quickeval | Before quick_evaluate |\n| #find_codeql_query_files | Discover related files | Planning, tracking changes |\n| #codeql_test_accept | Accept actual results as expected | After verifying correct output |\n| #profile_codeql_query_from_logs | Performance analysis | Optimization |\n\n## Interpreting Graph Query Results\n\nWhen running `PrintAST` or `PrintCFG`, the results are stored in BQRS format. To convert to readable text:\n\n```typescript\n// After codeql_query_run produces results.bqrs\ncodeql_bqrs_interpret: {\n file: "/path/to/results.bqrs",\n format: "graphtext",\n output: "/path/to/output.txt",\n t: ["kind=graph", "id=java/tools/print-ast"]\n}\n```\n\n**Note**: The output may create a directory structure (e.g., `output.txt/java/tools/print-ast.txt`) rather than a single file.\n\n## Example: Workshop Development\n\nWhen creating CodeQL workshops, this advanced methodology is essential:\n\n1. **Analyze production query** with #find_codeql_query_files\n2. **Generate AST/CFG** for workshop test code\n3. **Decompose query** into stages, validating each with #quick_evaluate\n4. **Create exercises** with scaffolding based on AST understanding\n5. **Validate solutions** ensure each stage produces correct results\n\n### Exercise Design Tips\n\nWhen creating exercise stubs from solutions:\n\n```ql\n// Use none() as placeholder in characteristic predicates\nclass MyPattern extends MethodCall {\n MyPattern() {\n // TODO: Implement - check for methods named "targetMethod"\n // Hint: Use this.getMethod().hasName(...)\n none()\n }\n}\n```\n\n- **Include TODO comments** with specific hints\n- **Reference AST class names** students should look for\n- **Build incrementally** - each exercise should build on the previous\n- **Test both exercises and solutions** to ensure expected files are accurate\n\nSee the `create-codeql-query-development-workshop` skill for complete workshop creation guidance.\n\n## Related Resources\n\n- **Basic TDD**: `codeql://prompts/ql-tdd-basic`\n- **AST Reference**: `codeql://languages/{language}/ast`\n- **Security Patterns**: `codeql://languages/{language}/security`\n- **Performance Guide**: `codeql://patterns/performance`\n- **Workshop Skill**: `.github/skills/create-codeql-query-development-workshop/SKILL.md`\n- **Tools Validation**: `.github/skills/validate-ql-mcp-server-tools-queries/SKILL.md`\n';
|
|
64272
|
+
var ql_tdd_advanced_prompt_default = '---\nagent: agent\n---\n\n# Advanced Test-Driven CodeQL Query Development\n\nThis advanced guide builds on the basic TDD methodology with powerful MCP server tools for deeper code analysis. Use this when developing complex queries that require understanding AST structure, control flow, and call relationships.\n\nFor basic TDD workflow, see: `codeql://prompts/ql-tdd-basic`\n\n## When to Use This Advanced Guide\n\n- **Complex AST patterns**: When you need to understand how CodeQL represents specific language constructs\n- **Control flow queries**: When analyzing program flow, branching, or loop structures\n- **Call graph analysis**: When tracing function calls or method invocations\n- **Iterative refinement**: When debugging queries that don\'t produce expected results\n- **Performance optimization**: When understanding query evaluation patterns\n\n## Core Advanced Tools\n\n### 1. AST/CFG Visualization with #codeql_query_run\n\nUse the bundled tools queries to visualize code structure:\n\n```typescript\n// Generate Abstract Syntax Tree for test code\ncodeql_query_run: {\n queryName: "PrintAST",\n queryLanguage: "java", // or "javascript", "python", "cpp", etc.\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/ast-output.txt"\n}\n\n// Generate Control Flow Graph\ncodeql_query_run: {\n queryName: "PrintCFG",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/cfg-output.txt"\n}\n\n// Analyze outbound calls from a function\ncodeql_query_run: {\n queryName: "CallGraphFrom",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n sourceFunction: "myFunction",\n format: "sarif-latest"\n}\n\n// Analyze inbound calls to a function\ncodeql_query_run: {\n queryName: "CallGraphTo",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n targetFunction: "targetMethod",\n format: "sarif-latest"\n}\n```\n\n**Critical**: Always verify that tools queries return **non-empty output** with actual nodes/edges, not just headers.\n\n### 2. Quick Evaluation with #quick_evaluate\n\nUse #quick_evaluate for rapid iteration on specific predicates or classes:\n\n```typescript\n// First, find the position of a predicate\nfind_predicate_position: {\n file: "/path/to/Query.ql",\n name: "isVulnerableSink"\n}\n\n// Then evaluate just that predicate\nquick_evaluate: {\n file: "/path/to/Query.ql",\n db: "/path/to/test.testproj",\n symbol: "isVulnerableSink",\n output_path: "/tmp/quickeval.bqrs"\n}\n\n// Or evaluate a specific class\n// NOTE: find_class_position finds `class` definitions only, not `module` definitions.\n// Use search_ql_code to find module definitions or other patterns across QL files.\nfind_class_position: {\n file: "/path/to/Query.ql",\n name: "ThrowingMethodCall"\n}\n\nquick_evaluate: {\n file: "/path/to/Query.ql",\n db: "/path/to/test.testproj",\n symbol: "ThrowingMethodCall"\n}\n```\n\n### 3. LSP-Powered Code Navigation\n\nUse the LSP tools for real-time code exploration during query development:\n\n```typescript\n// Discover available types after `import javascript`\ncodeql_lsp_completion: {\n file_path: "/path/to/Query.ql",\n line: 5, // 0-based line with `from` clause\n character: 5, // 0-based column position\n workspace_uri: "/path/to/pack-root" // REQUIRED: directory containing codeql-pack.yml\n}\n\n// Navigate to a class definition to see its predicates\ncodeql_lsp_definition: {\n file_path: "/path/to/Query.ql",\n line: 5, // 0-based line containing the class name\n character: 10, // 0-based column on the class name\n workspace_uri: "/path/to/pack-root"\n}\n\n// Find all usages of a predicate across the pack\ncodeql_lsp_references: {\n file_path: "/path/to/Query.ql",\n line: 8,\n character: 5,\n workspace_uri: "/path/to/pack-root"\n}\n```\n\n**Important LSP tool notes**:\n\n- `workspace_uri` must be a **plain directory path** (not a `file://` URI) pointing to the pack root containing `codeql-pack.yml`\n- All LSP tools use **0-based** line/character positions\n- #find_predicate_position and #find_class_position return **1-based** positions \u2014 subtract 1 before passing to LSP tools\n- Run #codeql_pack_install before using LSP tools \u2014 they require resolved dependencies\n- Request completions **after a dot** (e.g., `pw.`) to see all member predicates with full documentation\n\n### 4. Query File Discovery with #find_codeql_query_files\n\nUse this tool frequently to understand query dependencies and test structure:\n\n```typescript\nfind_codeql_query_files: {\n queryPath: \'/path/to/Query.ql\';\n}\n// Returns: query file, test directory, test files, metadata, dependencies\n```\n\n## Advanced TDD Workflow\n\n### Phase 0: Test Environment Setup (Critical for Java)\n\nFor Java tests that depend on external libraries (JUnit, etc.), create an `options` file in each test directory:\n\n```text\n//semmle-extractor-options: --javac-args -cp ${testdir}/../../stubs/junit-4.13:${testdir}/../../stubs/junit-jupiter-api-5.2.0\n```\n\n**Key points**:\n\n- `${testdir}` is relative to the test directory containing the `options` file\n- Use `:` (colon) to separate multiple classpath entries\n- Stub files must contain minimal class/interface definitions for compilation\n\n### Phase 1: Deep Code Analysis\n\nBefore writing any query logic:\n\n1. **Extract test database**:\n\n ```typescript\n codeql_test_extract: {\n testPath: "/path/to/test/QueryTest",\n searchPath: "/path/to/pack"\n }\n ```\n\n2. **Generate and study the AST**:\n\n ```typescript\n codeql_query_run: {\n queryName: "PrintAST",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/ast.txt"\n }\n ```\n\n3. **Identify key AST classes and predicates** from the output:\n - Note the class names (e.g., `MethodCall`, `TryStmt`, `LambdaExpr`)\n - Note parent-child relationships\n - Identify which nodes correspond to your test cases\n\n4. **Generate CFG if analyzing control flow**:\n\n ```typescript\n codeql_query_run: {\n queryName: "PrintCFG",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/cfg.txt"\n }\n ```\n\n### Phase 2: Iterative Predicate Development\n\nInstead of writing the full query at once:\n\n1. **Start with a single class or predicate**:\n\n ```ql\n class MyPattern extends MethodCall {\n MyPattern() {\n this.getMethod().hasName("targetMethod")\n }\n }\n ```\n\n2. **Use #quick_evaluate to test it**:\n\n ```typescript\n quick_evaluate: {\n file: "/path/to/Query.ql",\n db: "/path/to/test.testproj",\n symbol: "MyPattern"\n }\n ```\n\n3. **Refine based on results**:\n - Too many results? Add constraints\n - Too few results? Relax constraints\n - Wrong results? Study AST output again\n\n4. **Repeat for each component** before combining\n\n### Phase 3: Incremental Query Assembly\n\n1. **Combine validated predicates** into the main query\n2. **Run full tests** after each combination:\n\n ```typescript\n codeql_test_run: {\n testPath: "/path/to/test/QueryTest",\n searchPath: "/path/to/pack"\n }\n ```\n\n3. **Use #find_codeql_query_files** to track all related files:\n\n ```typescript\n find_codeql_query_files: {\n queryPath: \'/path/to/Query.ql\';\n }\n ```\n\n## Common Advanced Patterns\n\n### Pattern: Understanding Nested Structures\n\nWhen your query involves nested constructs (e.g., lambdas inside method calls):\n\n```ql\n// First, find the outer construct\nclass OuterPattern extends MethodCall {\n OuterPattern() {\n this.getMethod().hasName("assertThrows")\n }\n\n // Navigate to inner construct\n Expr getLambdaBody() {\n exists(LambdaExpr le |\n le = this.getAChildExpr() and\n result = le.getExprBody()\n )\n }\n}\n```\n\nUse `PrintAST` to understand the parent-child relationships.\n\n### Pattern: Control Flow Dependencies\n\nWhen your query needs to understand execution order:\n\n```ql\n// Use CFG to understand which statements precede others\npredicate precedesInBlock(Stmt s1, Stmt s2) {\n exists(BasicBlock bb |\n s1.getBasicBlock() = bb and\n s2.getBasicBlock() = bb and\n s1.getLocation().getStartLine() < s2.getLocation().getStartLine()\n )\n}\n```\n\nUse `PrintCFG` to verify the control flow structure.\n\n### Pattern: Call Chain Analysis\n\nWhen tracing calls through multiple functions:\n\n```typescript\n// First, understand the call graph from your entry point\ncodeql_query_run: {\n queryName: "CallGraphFrom",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n sourceFunction: "entryPoint"\n}\n\n// Then trace back from your target\ncodeql_query_run: {\n queryName: "CallGraphTo",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n targetFunction: "sensitiveOperation"\n}\n```\n\n## Debugging Tips\n\n### When Results Are Empty\n\n1. **Check AST first**: Run `PrintAST` to verify the code structure matches expectations\n2. **Simplify the query**: Remove constraints one by one using #quick_evaluate\n3. **Check enclosing callables**: Lambda bodies may have different `getEnclosingCallable()` than expected\n4. **Verify test database extraction**: Ensure the `.testproj` directory was created successfully\n\n### When Results Are Incorrect\n\n1. **Quick evaluate individual predicates**: Isolate which part is wrong\n2. **Compare with AST output**: Verify your understanding of the structure\n3. **Check for missing cases**: Your pattern may not cover all code variations\n\n### When Compilation Fails with "override" Error\n\nIf you see `annotation \'override\' missing on predicate`, you\'ve accidentally created a predicate with the same name as one in the parent class. **Rename your predicate** to avoid the conflict:\n\n```ql\n// BAD: Method already has getAThrownExceptionType()\nclass ThrowingMethod extends Method {\n RefType getAThrownExceptionType() { ... } // Error!\n}\n\n// GOOD: Use a distinct name\nclass ThrowingMethod extends Method {\n RefType getDeclaredExceptionType() { ... } // Works\n}\n```\n\n### When Query Is Slow\n\n1. **Enable evaluator logs**:\n\n ```typescript\n codeql_query_run: {\n query: "/path/to/Query.ql",\n database: "/path/to/db",\n "evaluator-log": "/path/to/log.json",\n "evaluator-log-level": 5\n }\n ```\n\n2. **Profile from evaluator logs** (primary tool \u2014 returns compact JSON metrics plus a line-indexed detail file for targeted `read_file` access to RA operations and tuple progressions):\n\n ```typescript\n profile_codeql_query_from_logs: {\n evaluatorLog: \'/path/to/log.json\';\n }\n ```\n\n## Checklist for Complex Queries\n\n### Before Starting\n\n- [ ] Test database extracted successfully\n- [ ] `PrintAST` output reviewed and understood\n- [ ] Key AST classes identified\n- [ ] Test cases cover positive, negative, and edge cases\n\n### During Development\n\n- [ ] Each predicate/class tested with #quick_evaluate\n- [ ] #find_codeql_query_files used to track dependencies\n- [ ] CFG consulted for control flow patterns\n- [ ] Call graphs generated for cross-function analysis\n\n### After Each Change\n\n- [ ] Query compiles with #codeql_query_compile\n- [ ] Quick evaluation shows expected results\n- [ ] Full tests pass with #codeql_test_run\n- [ ] No duplicate or missing results\n\n### Final Validation\n\n- [ ] All test cases pass\n- [ ] No false positives in results\n- [ ] No false negatives (all expected cases caught)\n- [ ] Query formatted with #codeql_query_format\n- [ ] Performance acceptable (check with #profile_codeql_query_from_logs)\n\n## Test Acceptance Workflow\n\nWhen your query produces correct results but differs from the `.expected` file:\n\n1. **Review the `.actual` file** to verify results are correct\n2. **Accept the results** to update the expected baseline:\n\n ```typescript\n codeql_test_accept: {\n tests: [\'/path/to/test/QueryTest\'];\n }\n ```\n\n3. **Re-run tests** to confirm they now pass\n\n**Warning**: Only accept results after careful review. Don\'t blindly accept to make tests pass.\n\n## Tool Reference\n\n| Tool | Purpose | When to Use |\n| ------------------------------- | --------------------------------- | ------------------------------- |\n| #codeql_query_run (PrintAST) | Visualize AST structure | Start of development, debugging |\n| #codeql_query_run (PrintCFG) | Visualize control flow | Control flow queries |\n| #codeql_query_run (CallGraph\\*) | Analyze call relationships | Cross-function queries |\n| #codeql_bqrs_interpret | Convert BQRS to readable format | After running graph queries |\n| #quick_evaluate | Test individual predicates | Iterative development |\n| #find_predicate_position | Locate predicate for quickeval | Before quick_evaluate |\n| #find_class_position | Locate class for quickeval | Before quick_evaluate |\n| #find_codeql_query_files | Discover related files | Planning, tracking changes |\n| #search_ql_code | Search QL files for patterns | Finding classes, predicates |\n| #codeql_resolve_files | Find QL files by name/extension | Discovering library pack files |\n| #codeql_test_accept | Accept actual results as expected | After verifying correct output |\n| #profile_codeql_query_from_logs | Performance analysis | Optimization |\n\n## Interpreting Graph Query Results\n\nWhen running `PrintAST` or `PrintCFG`, the results are stored in BQRS format. To convert to readable text:\n\n```typescript\n// After codeql_query_run produces results.bqrs\ncodeql_bqrs_interpret: {\n file: "/path/to/results.bqrs",\n format: "graphtext",\n output: "/path/to/output.txt",\n t: ["kind=graph", "id=java/tools/print-ast"]\n}\n```\n\n**Note**: The output may create a directory structure (e.g., `output.txt/java/tools/print-ast.txt`) rather than a single file.\n\n## Example: Workshop Development\n\nWhen creating CodeQL workshops, this advanced methodology is essential:\n\n1. **Analyze production query** with #find_codeql_query_files\n2. **Generate AST/CFG** for workshop test code\n3. **Decompose query** into stages, validating each with #quick_evaluate\n4. **Create exercises** with scaffolding based on AST understanding\n5. **Validate solutions** ensure each stage produces correct results\n\n### Exercise Design Tips\n\nWhen creating exercise stubs from solutions:\n\n```ql\n// Use none() as placeholder in characteristic predicates\nclass MyPattern extends MethodCall {\n MyPattern() {\n // TODO: Implement - check for methods named "targetMethod"\n // Hint: Use this.getMethod().hasName(...)\n none()\n }\n}\n```\n\n- **Include TODO comments** with specific hints\n- **Reference AST class names** students should look for\n- **Build incrementally** - each exercise should build on the previous\n- **Test both exercises and solutions** to ensure expected files are accurate\n\nSee the `create-codeql-query-development-workshop` skill for complete workshop creation guidance.\n\n## Related Resources\n\n- **Basic TDD**: `codeql://prompts/ql-tdd-basic`\n- **AST Reference**: `codeql://languages/{language}/ast`\n- **Security Patterns**: `codeql://languages/{language}/security`\n- **Performance Guide**: `codeql://patterns/performance`\n- **Workshop Skill**: `.github/skills/create-codeql-query-development-workshop/SKILL.md`\n- **Tools Validation**: `.github/skills/validate-ql-mcp-server-tools-queries/SKILL.md`\n';
|
|
63855
64273
|
|
|
63856
64274
|
// src/prompts/ql-tdd-basic.prompt.md
|
|
63857
|
-
var ql_tdd_basic_prompt_default = '---\nagent: agent\n---\n\n# Test-Driven CodeQL Query Development Checklist\n\nUse this checklist to guide test-driven development of CodeQL queries. Follow the TDD cycle: write tests first, implement query logic, and iterate until tests pass.\n\nFor advanced techniques including AST/CFG visualization, see: `codeql://prompts/ql-tdd-advanced`\nFor detailed guidance, reference the MCP resource: `codeql://learning/test-driven-development`\n\n## TDD Workflow Checklist\n\n### Phase 1: Project Setup\n\n- [ ] **Create Query Structure**\n - Tool: #create_codeql_query\n - Specify: basePath, queryName, language, description (optional)\n - Creates: src/QueryName/QueryName.ql, test/QueryName/QueryName.qlref, test/QueryName/test-code-file\n - The .qlref file will contain the relative path: `QueryName/QueryName.ql`\n - Verify: directory structure follows CodeQL conventions with intermediate directories\n\n- [ ] **Install Pack Dependencies**\n - Tool: #codeql_pack_install\n - Install src pack dependencies\n - Install test pack dependencies\n - Verify: imports resolve without errors\n\n### Phase 2: Test Design (Red Phase)\n\n- [ ] **Design Test Cases**\n - Create positive test cases (should match)\n - Create negative test cases (should not match)\n - Create edge case tests\n - Document expected behavior in comments\n\n- [ ] **Define Expected Results**\n - Create .expected file with anticipated matches\n - Specify exact match locations (file, line, column)\n - Include expected alert messages\n\n- [ ] **Extract Test Database**\n - Tool: #codeql_test_extract\n - Extract database from test code\n - Verify: .testproj directory created\n\n### Phase 3: Analysis and Understanding\n\n- [ ] **Analyze Test Code AST**\n - Tool: #codeql_query_run with queryName: "PrintAST"\n - Use format: "graphtext" for @kind graph queries\n - Review AST structure and identify relevant classes\n\n- [ ] **Explore Available Classes and Predicates**\n - Tool: #codeql_lsp_completion at the position in the `from` clause\n - Parameters: `file_path`, `line` (0-based), `character` (0-based)\n - Set `workspace_uri` to the pack root directory (containing `codeql-pack.yml`)\n - Request completions after a dot (e.g., `pw.`) to see member predicates with docs\n - Tip: Run #codeql_pack_install first \u2014 LSP tools require resolved dependencies\n\n- [ ] **Navigate to Type Definitions**\n - Tool: #codeql_lsp_definition on a class or predicate name\n - Parameters: `file_path`, `line` (0-based), `character` (0-based), `workspace_uri`\n - Returns file URI and line range \u2014 even into library pack files\n - Read the definition source to understand available member predicates\n - Tool: #codeql_lsp_references to find usage examples across the pack\n\n For the full iterative LSP workflow, see: `codeql://prompts/ql_lsp_iterative_development`\n\n- [ ] **Reference Language Documentation**\n - Resource: `codeql://languages/{language}/ast`\n - Resource: `codeql://languages/{language}/security` (if applicable)\n - Identify AST classes and predicates needed\n\n### Phase 4: Implementation (Green Phase)\n\n- [ ] **Write Query Metadata**\n - Add @name annotation\n - Add @description annotation\n - Add @kind annotation (problem, path-problem, graph, etc.)\n - Add @id and other required metadata\n\n- [ ] **Implement Query Logic**\n - Import required libraries\n - Define necessary classes (if any)\n - Define helper predicates\n - Implement main query clause\n\n- [ ] **Compile Query**\n - Tool: #codeql_query_compile\n - Fix any compilation errors\n - Verify: query compiles successfully\n\n- [ ] **Run Tests**\n - Tool: #codeql_test_run\n - Compare actual vs expected results\n - If tests fail: adjust query logic and recompile\n - If tests pass: proceed to validation\n\n### Phase 5: Validation and Acceptance\n\n- [ ] **Verify Test Results**\n - Review all test matches\n - Confirm no false positives\n - Confirm no false negatives\n - Check edge cases behave correctly\n\n- [ ] **Accept Test Results** (only when correct)\n - Tool: #codeql_test_accept\n - Update .expected files\n - Commit accepted results\n\n### Phase 6: Refactoring and Enhancement\n\n- [ ] **Refactor Query**\n - Improve code clarity\n - Extract common logic to predicates\n - Add code comments and documentation\n - Tool: #codeql_query_format for consistent formatting\n\n- [ ] **Optimize Performance** (if needed)\n - Run with evaluator-log enabled\n - Tool: #
|
|
64275
|
+
var ql_tdd_basic_prompt_default = '---\nagent: agent\n---\n\n# Test-Driven CodeQL Query Development Checklist\n\nUse this checklist to guide test-driven development of CodeQL queries. Follow the TDD cycle: write tests first, implement query logic, and iterate until tests pass.\n\nFor advanced techniques including AST/CFG visualization, see: `codeql://prompts/ql-tdd-advanced`\nFor detailed guidance, reference the MCP resource: `codeql://learning/test-driven-development`\n\n## TDD Workflow Checklist\n\n### Phase 1: Project Setup\n\n- [ ] **Create Query Structure**\n - Tool: #create_codeql_query\n - Specify: basePath, queryName, language, description (optional)\n - Creates: src/QueryName/QueryName.ql, test/QueryName/QueryName.qlref, test/QueryName/test-code-file\n - The .qlref file will contain the relative path: `QueryName/QueryName.ql`\n - Verify: directory structure follows CodeQL conventions with intermediate directories\n\n- [ ] **Install Pack Dependencies**\n - Tool: #codeql_pack_install\n - Install src pack dependencies\n - Install test pack dependencies\n - Verify: imports resolve without errors\n\n### Phase 2: Test Design (Red Phase)\n\n- [ ] **Design Test Cases**\n - Create positive test cases (should match)\n - Create negative test cases (should not match)\n - Create edge case tests\n - Document expected behavior in comments\n\n- [ ] **Define Expected Results**\n - Create .expected file with anticipated matches\n - Specify exact match locations (file, line, column)\n - Include expected alert messages\n\n- [ ] **Extract Test Database**\n - Tool: #codeql_test_extract\n - Extract database from test code\n - Verify: .testproj directory created\n\n### Phase 3: Analysis and Understanding\n\n- [ ] **Analyze Test Code AST**\n - Tool: #codeql_query_run with queryName: "PrintAST"\n - Use format: "graphtext" for @kind graph queries\n - Review AST structure and identify relevant classes\n\n- [ ] **Explore Available Classes and Predicates**\n - Tool: #codeql_lsp_completion at the position in the `from` clause\n - Parameters: `file_path`, `line` (0-based), `character` (0-based)\n - Set `workspace_uri` to the pack root directory (containing `codeql-pack.yml`)\n - Request completions after a dot (e.g., `pw.`) to see member predicates with docs\n - Tip: Run #codeql_pack_install first \u2014 LSP tools require resolved dependencies\n\n- [ ] **Navigate to Type Definitions**\n - Tool: #codeql_lsp_definition on a class or predicate name\n - Parameters: `file_path`, `line` (0-based), `character` (0-based), `workspace_uri`\n - Returns file URI and line range \u2014 even into library pack files\n - Read the definition source to understand available member predicates\n - Tool: #codeql_lsp_references to find usage examples across the pack\n\n For the full iterative LSP workflow, see: `codeql://prompts/ql_lsp_iterative_development`\n\n- [ ] **Reference Language Documentation**\n - Resource: `codeql://languages/{language}/ast`\n - Resource: `codeql://languages/{language}/security` (if applicable)\n - Identify AST classes and predicates needed\n\n### Phase 4: Implementation (Green Phase)\n\n- [ ] **Write Query Metadata**\n - Add @name annotation\n - Add @description annotation\n - Add @kind annotation (problem, path-problem, graph, etc.)\n - Add @id and other required metadata\n\n- [ ] **Implement Query Logic**\n - Import required libraries\n - Define necessary classes (if any)\n - Define helper predicates\n - Implement main query clause\n\n- [ ] **Compile Query**\n - Tool: #codeql_query_compile\n - Fix any compilation errors\n - Verify: query compiles successfully\n\n- [ ] **Run Tests**\n - Tool: #codeql_test_run\n - Compare actual vs expected results\n - If tests fail: adjust query logic and recompile\n - If tests pass: proceed to validation\n\n### Phase 5: Validation and Acceptance\n\n- [ ] **Verify Test Results**\n - Review all test matches\n - Confirm no false positives\n - Confirm no false negatives\n - Check edge cases behave correctly\n\n- [ ] **Accept Test Results** (only when correct)\n - Tool: #codeql_test_accept\n - Update .expected files\n - Commit accepted results\n\n### Phase 6: Refactoring and Enhancement\n\n- [ ] **Refactor Query**\n - Improve code clarity\n - Extract common logic to predicates\n - Add code comments and documentation\n - Tool: #codeql_query_format for consistent formatting\n\n- [ ] **Optimize Performance** (if needed)\n - Run with evaluator-log enabled\n - Tool: #profile_codeql_query_from_logs\n - Resource: `codeql://patterns/performance`\n - Optimize expensive operations\n\n- [ ] **Generate Documentation**\n - Tool: #codeql_generate_query_help\n - Review and enhance QLDoc comments\n - Document query purpose and limitations\n\n### Phase 7: Additional Testing\n\n- [ ] **Add More Test Cases**\n - Identify additional scenarios\n - Add tests for new edge cases\n - Extract new test databases\n - Run expanded test suite\n\n- [ ] **Validate Against Real Code** (optional)\n - Tool: #codeql_database_create for real codebase\n - Tool: #codeql_query_run against real database\n - Review results for false positives/negatives\n\n## Quick Command Reference\n\n### Essential Tools\n\n```typescript\n// Create query structure\ncreate_codeql_query: {\n basePath: "/path/to/query/base",\n queryName: "MySecurityQuery",\n language: "javascript",\n description: "Detects security vulnerability X"\n}\n\n// Install dependencies\ncodeql_pack_install: {\n packPath: "/path/to/pack"\n}\n\n// Extract test database\ncodeql_test_extract: {\n testPath: "/path/to/test/QueryName",\n searchPath: "/path/to/base"\n}\n\n// Analyze AST (for @kind graph queries)\ncodeql_query_run: {\n queryName: "PrintAST",\n queryLanguage: "javascript",\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/ast-output/"\n}\n\n// Compile query\ncodeql_query_compile: {\n query: "/path/to/Query.ql",\n searchPath: "/path/to/base",\n checkOnly: true\n}\n\n// Run tests\ncodeql_test_run: {\n testPath: "/path/to/test/Query.qlref",\n searchPath: "/path/to/base"\n}\n\n// Accept results\ncodeql_test_accept: {\n testPath: "/path/to/test/Query",\n searchPath: "/path/to/base"\n}\n```\n\n## TDD Principles to Remember\n\n1. **Red \u2192 Green \u2192 Refactor**: Always start with failing tests\n2. **Test First**: Write tests before implementation\n3. **Small Steps**: Make minimal changes to pass each test\n4. **Frequent Testing**: Run tests after each change\n5. **One Concept Per Test**: Each test should verify one behavior\n6. **Keep Tests Simple**: Test code should be easy to understand\n7. **Refactor Confidently**: Tests enable safe refactoring\n\n## Common Pitfalls to Avoid\n\n- \u274C Writing query before tests\n- \u274C Accepting test results without verification\n- \u274C Skipping compilation step\n- \u274C Not using PrintAST to understand test code\n- \u274C Not using #codeql_lsp_completion to discover available types\n- \u274C Not setting `workspace_uri` when using LSP tools (completions will be empty)\n- \u274C Creating tests that are too complex\n- \u274C Ignoring false positives in results\n- \u274C Not refactoring after tests pass\n\n## Success Criteria\n\nYour query development is complete when:\n\n- \u2705 All tests pass\n- \u2705 No false positives in test results\n- \u2705 No false negatives (all expected cases caught)\n- \u2705 Query compiles without errors or warnings\n- \u2705 Code is well-documented with QLDoc comments\n- \u2705 Performance is acceptable\n- \u2705 Edge cases are covered by tests\n- \u2705 Query follows CodeQL best practices\n\n## Next Steps After Completion\n\n1. **Integration Testing**: Test against real codebases\n2. **Peer Review**: Have another developer review the query\n3. **Documentation**: Update project documentation\n4. **Regression Testing**: Add to CI/CD pipeline\n5. **Monitor Performance**: Track query performance over time\n';
|
|
63858
64276
|
|
|
63859
64277
|
// src/prompts/run-query-and-summarize-false-positives.prompt.md
|
|
63860
64278
|
var run_query_and_summarize_false_positives_prompt_default = '---\nagent: agent\n---\n\n# Run a query and describe its false positives\n\n## Task\n\nHelp a developer discover what kinds of false positives are produced by their current CodeQL query, and which of those false positive cases are most common.\n\n### Task steps:\n\n1. Read the provided CodeQL query to understand what patterns it is designed to detect.\n2. Discover the results of this query on a real database, by:\n - Running the tool #list_query_run_results to find existing runs for this query\n - If no existing runs are found, run the query on a relevant database using #codeql_query_run tool\n3. Analyze and group the results into what appear to be similar types of results. This may mean:\n - Grouping results in the same file\n - Grouping results that reference the same elements\n - Grouping results with similar messages\n4. For each group, explore the actual code for a sample of alerts in that group, using the #read_database_source tool to triage the results and determine which groups appear to be false positives\n5. For each false positive case discovered in this exploration, group them into categories of similar root causes. For example, a query might not properly account for unreachable code, or there may be a commonly used library that violates the query\'s assumptions but is actually safe.\n6. Explain these results to the user in order of most common to least common, so they can understand where their query may need improvement to reduce false positives.\n\n## Input Context\n\nYou will be provided with:\n\n- **Query Path**: The path to the CodeQL query\n\n## Analysis Guidelines\n\n### Exploring code paths\n\nThe tool #read_database_source can be used to read the code of a particular finding. A good strategy to explore the code paths of a finding is:\n\n1. Read in the immediate context of the violation.\n - Some queries may depend on later context (e.g., an "unused variable" may only be used after its declaration)\n - Some queries may depend on earlier context (e.g., "mutex not initialized" requires observing code that ran before the violation)\n - Some queries may rely on exploring other function calls.\n2. Read the interprocedural context of the violation.\n - If understanding a violation requires checking other source locations, read the beginning of the file to find what it imports, and then read those imported files to find the relevant code.\n - Selectively scan interprocedural paths. A false positive that requires tremendous code exploration to verify is less problematic than a false positive that only requires checking a small amount of code to verify.\n3. Stop early.\n - Grouping the potential false positive cases is more important than exhaustively verifying every single finding.\n - A common false positive likely introduces some false positives that are very hard to verify, so it is usually better to focus on simple cases first.\n - Truly hard-to-verify false positive cases are often in code that users don\'t expect to be conducive to static analysis, and query authors often don\'t expect their queries to work well in those cases.\n - Suggest a chainsaw approach rather than a scalpel - if a result may be a false positive, identify some simple heuristics to eliminate all such complex cases, even if such a heuristic could introduce false negatives.\n\n### What Makes a Result Likely to be a False Positive?\n\n1. **Pattern Mismatches**\n - Query pattern doesn\'t accurately match the actual code behavior\n - Missing context that would show the code is safe\n - Overly broad query logic catching benign variations\n\n2. **Safe Code Patterns**\n - Code includes proper validation before the flagged operation\n - Results in test code, example code, or mock implementations\n - Variable/function names suggesting test/example context (e.g., `testFunc`, `exampleVar`, `mockData`)\n - Defensive programming patterns present but not recognized by query\n\n3. **Context Indicators**\n - File paths suggesting test/example files (e.g., `test/`, `examples/`, `mock/`)\n - Comments indicating intentional patterns or safe usage\n - Framework-specific patterns that are safe in context\n\n4. **Technical Factors**\n - Type mismatches that make the vulnerability impossible\n - Control flow that prevents exploitation\n - Data flow interrupted by sanitization not captured in query\n\n### Important Constraints\n\n- **Be objective**: Don\'t be influenced by variable/function naming suggesting importance (e.g., "prodOnly" vs "test")\n- **Require evidence**: Base conclusions on actual code patterns, not assumptions\n- **Mark uncertainty**: Use lower confidence scores when code snippets are missing\n- **Avoid false confidence**: If you cannot determine FP status, mark confidence as low\n\n## Output Format\n\nReturn a JSON array of false-positive _groups_, ordered by the estimated prevalence or importance of the false-positive pattern (highest first):\n\n```json\n[\n {\n "groupLabel": "Test and example code with safe validation",\n "patternSummary": "Results where the flagged operation occurs in test/example files and is always preceded by input validation.",\n "resultCount": 23,\n "estimatedFpProportion": 0.9,\n "confidence": 0.85,\n "commonRootCause": "The query does not recognize common test/example locations or custom validation helpers as making the pattern safe.",\n "sampleResults": [\n {\n "sourceFile": "results-1.sarif",\n "resultIndex": 42,\n "ruleId": "query-id",\n "message": { "text": "original result message" },\n "locations": []\n }\n ],\n "reasoning": "Based on manual inspection of several alerts in this group: (1) results are consistently located under \'test/\' or \'examples/\' directories, (2) there is clear validation before the flagged operation, and (3) the query does not model the custom validation helpers used in these files."\n }\n]\n```\n\n### Field Descriptions\n\n- **groupLabel**: Short human-readable name for the false-positive category.\n- **patternSummary**: One-sentence description of the common pattern shared by results in this group.\n- **resultCount**: Number of SARIF results that belong to this group.\n- **estimatedFpProportion**: Estimated proportion of results in this group that are false positives (0.0\u20131.0).\n- **confidence**: Confidence in the group-level assessment (see guidelines below).\n- **commonRootCause**: Why the query produces false positives for this pattern.\n- **sampleResults**: A small representative sample of results illustrating the pattern.\n- **reasoning**: Detailed explanation of how the FP determination was made.\n\n### Confidence Score Guidelines\n\n- **0.8-1.0**: Strong evidence of FP (e.g., test code with clear safety patterns)\n- **0.6-0.8**: Good evidence of FP (e.g., defensive patterns present)\n- **0.4-0.6**: Moderate evidence of FP (e.g., context suggests safety but not conclusive)\n- **0.2-0.4**: Weak evidence of FP (e.g., minor indicators, missing code snippets)\n- **0.0-0.2**: Minimal evidence (uncertain, need more information)\n\n## Examples\n\n### High-Confidence FP Group Example\n\n```json\n{\n "groupLabel": "Sanitised inputs in test harnesses",\n "patternSummary": "Results in test files where sanitizeInput() is called before the database query.",\n "resultCount": 15,\n "estimatedFpProportion": 0.95,\n "confidence": 0.9,\n "commonRootCause": "Query does not model sanitizeInput() as a sanitizer.",\n "sampleResults": [\n {\n "sourceFile": "results-1.sarif",\n "resultIndex": 7,\n "ruleId": "js/sql-injection",\n "message": { "text": "Potential SQL injection" },\n "locations": []\n }\n ],\n "reasoning": "False positive group: (1) File paths like \'test/unit/database-mock.test.js\' indicate test code, (2) Query doesn\'t recognize that \'sanitizeInput()\' is called before database query, (3) All 15 results share this pattern."\n}\n```\n\n### Low-Confidence FP Group Example\n\n```json\n{\n "groupLabel": "File utility handlers with unclear validation",\n "patternSummary": "Results in src/utils/ files where path validation may or may not be present.",\n "resultCount": 4,\n "estimatedFpProportion": 0.5,\n "confidence": 0.3,\n "commonRootCause": "Unclear whether custom path validation is sufficient.",\n "sampleResults": [\n {\n "sourceFile": "results-1.sarif",\n "resultIndex": 22,\n "ruleId": "js/path-injection",\n "message": { "text": "Potential path traversal" },\n "locations": []\n }\n ],\n "reasoning": "Possibly false positive: (1) No code snippets available in SARIF, (2) File path \'src/utils/fileHandler.js\' doesn\'t indicate test code, (3) Cannot verify if proper path validation exists. Low confidence due to missing context."\n}\n```\n\n## Processing Instructions\n\n1. **Review SARIF results** and group them by common patterns\n2. **Analyze available context** (code snippets, file paths, messages) for each group\n3. **Compare against query logic** to understand what pattern was detected\n4. **Identify FP indicators** based on guidelines above\n5. **Assign group-level confidence scores** reflecting evidence strength\n6. **Write clear reasoning** for each group explaining the assessment\n7. **Sort groups** by estimated prevalence / importance (descending)\n\n## Important Notes\n\n- A result should belong to at most one FP group\n- When in doubt, prefer lower confidence scores\n- Missing code snippets should always reduce confidence\n- Test/example code is more likely to be FP but not always\n- Focus on technical evidence, not code naming conventions\n';
|
|
@@ -63866,7 +64284,7 @@ var sarif_rank_false_positives_prompt_default = '---\nagent: agent\n---\n\n# Eva
|
|
|
63866
64284
|
var sarif_rank_true_positives_prompt_default = '---\nagent: agent\n---\n\n# Evaluate SARIF Results for True Positives\n\n## Task\n\nAnalyze SARIF results from a CodeQL query and identify the most likely **True Positives (TPs)** - results that correctly identify real security vulnerabilities or code quality issues.\n\n## Input Context\n\nYou will be provided with:\n\n- **Query ID**: The CodeQL query/rule identifier\n- **Query Name**: Human-readable name of the query\n- **Query Content**: Full CodeQL query implementation\n- **SARIF Results**: Array of results to analyze\n- **Code Snippets**: When available, code snippets from SARIF physical locations\n\n## Analysis Guidelines\n\n### What Makes a Result Likely to be a True Positive?\n\n1. **Pattern Matches**\n - Query pattern accurately identifies the problematic code behavior\n - Result shows clear evidence of the vulnerability or issue\n - Code matches the exact pattern the query was designed to detect\n\n2. **Vulnerable Code Patterns**\n - User input flows to dangerous sink without proper sanitization\n - Missing security checks or validation\n - Incorrect use of security-sensitive APIs\n - Clear violation of security best practices\n\n3. **Production Code Context**\n - File paths suggesting production code (e.g., `src/`, `lib/`, `app/`)\n - NOT in test/example directories\n - Function/variable names suggesting real business logic\n - Code appears to be part of actual application functionality\n\n4. **Technical Factors**\n - Data flow from untrusted source to dangerous operation\n - Missing or insufficient sanitization\n - Exploitable control flow\n - Real security or quality implications\n\n### Important Constraints\n\n- **Be objective**: Don\'t be influenced by variable/function naming suggesting importance\n- **Require evidence**: Base conclusions on actual vulnerability patterns, not assumptions\n- **Mark uncertainty**: Use lower confidence scores when code snippets are missing\n- **Avoid false confidence**: If you cannot determine TP status, mark confidence as low\n- **Consider false positives**: Be skeptical - real vulnerabilities often have subtle mitigations\n\n### When Code Snippets Are Missing\n\nIf SARIF results lack `physicalLocation.region.snippet` or `contextRegion`:\n\n- **Lower confidence scores** (typically 0.3-0.5 instead of 0.6-0.9)\n- **Note the limitation** in reasoning\n- **Rely more on**:\n - Result message text\n - File path analysis\n - Query logic understanding\n\n## Output Format\n\nReturn a JSON array of ranked results, ordered by TP likelihood (highest first):\n\n```json\n[\n {\n "ruleId": "query-id",\n "message": { "text": "original result message" },\n "locations": [...],\n "confidence": 0.85,\n "reasoning": "This appears to be a true positive because: (1) the file path \'src/api/user-controller.js\' indicates production code, (2) user input from request parameter flows directly to SQL query without sanitization, (3) no validation or prepared statement usage detected.",\n "sourceFile": "results-1.sarif",\n "resultIndex": 15\n }\n]\n```\n\n### Confidence Score Guidelines\n\n- **0.8-1.0**: Strong evidence of TP (e.g., clear vulnerability with exploit path)\n- **0.6-0.8**: Good evidence of TP (e.g., production code with problematic pattern)\n- **0.4-0.6**: Moderate evidence of TP (e.g., pattern matches but context unclear)\n- **0.2-0.4**: Weak evidence of TP (e.g., possible issue but missing context)\n- **0.0-0.2**: Minimal evidence (uncertain, need more information)\n\n## Examples\n\n### High-Confidence TP Example\n\n```json\n{\n "ruleId": "js/sql-injection",\n "message": { "text": "Unsanitized user input in SQL query" },\n "confidence": 0.9,\n "reasoning": "True positive: (1) File path \'src/controllers/UserController.js\' indicates production code, (2) User input from req.query.userId flows directly to SQL query string concatenation, (3) No prepared statements or sanitization visible in code snippet, (4) Classic SQL injection pattern. Confidence is 0.9 not 1.0 due to possibility of sanitization elsewhere in call chain."\n}\n```\n\n### Moderate-Confidence TP Example\n\n```json\n{\n "ruleId": "js/path-injection",\n "message": { "text": "Potential path traversal vulnerability" },\n "confidence": 0.6,\n "reasoning": "Likely true positive: (1) File path \'src/utils/fileHandler.js\' suggests production utility code, (2) User-controlled filename parameter used in fs.readFile(), (3) No visible path validation, but code snippet is limited. Moderate confidence due to incomplete context - may have validation in calling code."\n}\n```\n\n### Low-Confidence TP Example (Missing Snippets)\n\n```json\n{\n "ruleId": "java/unsafe-deserialization",\n "message": { "text": "Unsafe deserialization of user data" },\n "confidence": 0.4,\n "reasoning": "Possibly a true positive: (1) File path \'src/main/java/com/app/handlers/DataHandler.java\' indicates production code, (2) Message suggests unsafe deserialization pattern, (3) No code snippets available in SARIF to verify actual vulnerability or confirm absence of mitigations. Confidence is low due to missing context."\n}\n```\n\n## Processing Instructions\n\n1. **Review each SARIF result** in the provided array\n2. **Analyze available context** (code snippets, file paths, messages)\n3. **Compare against query logic** to understand what pattern was detected\n4. **Identify TP indicators** based on guidelines above\n5. **Look for counter-evidence** (mitigations, safe patterns) that would make it an FP\n6. **Assign confidence score** reflecting evidence strength\n7. **Write clear reasoning** explaining your assessment\n8. **Sort results** by confidence score (descending)\n9. **Return top N results** as requested (or all if N not specified)\n\n## Important Notes\n\n- A result should never appear in both FP and TP rankings\n- When in doubt, prefer lower confidence scores\n- Missing code snippets should always reduce confidence\n- Production code location increases TP likelihood but is not conclusive\n- Focus on technical vulnerability evidence, not code naming conventions\n- Consider that even production code can have intentional patterns that look vulnerable but are safe\n';
|
|
63867
64285
|
|
|
63868
64286
|
// src/prompts/tools-query-workflow.prompt.md
|
|
63869
|
-
var tools_query_workflow_prompt_default = '---\nagent: agent\n---\n\n# Using CodeQL Development MCP Server Tools Queries\n\nThis guide helps you use the built-in "tools" queries (`PrintAST`, `PrintCFG`, `CallGraphFrom`, `CallGraphTo`) that ship with the CodeQL Development MCP Server to understand code structure before writing detection queries.\n\n## Why Use Tools Queries?\n\nTools queries provide essential insights into how CodeQL represents your source code:\n\n| Query | Purpose | Use When |\n| --------------- | ------------------------------------------------ | ----------------------------------------------- |\n| `PrintAST` | Visualize the Abstract Syntax Tree | Understanding code structure, finding AST nodes |\n| `PrintCFG` | Visualize Control Flow Graphs | Understanding execution paths, loop/branch flow |\n| `CallGraphFrom` | Find all functions called by a specific function | Tracing data flow through call chains |\n| `CallGraphTo` | Find all functions that call a specific function | Understanding function usage patterns |\n\n## Supported Languages\n\nTools queries are available for: `actions`, `cpp`, `csharp`, `go`, `java`, `javascript`, `python`, `ruby`, `swift`\n\n## Prerequisites\n\nBefore using tools queries, you need:\n\n1. **A CodeQL database** - Either create one or use an existing database\n2. **Source files to analyze** - The tools queries filter output to specific files\n\n## Workflow Checklist\n\n### Step 1: Identify or Create Database\n\n- [ ] **Option A: Use existing database**\n - Tool: #codeql_resolve_database\n - Verify database is valid and note the language\n\n- [ ] **Option B: Create new database**\n - Tool: #codeql_database_create\n - Parameters: `database`, `language`, `source-root`\n\n### Step 2: Run PrintAST Query\n\nThe PrintAST query outputs a hierarchical tree of AST nodes with labels.\n\n- [ ] **Execute PrintAST**\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"PrintAST"`\n - `queryLanguage`: Your language (e.g., `"javascript"`, `"python"`, `"cpp"`)\n - `sourceFiles`: Comma-separated file names to analyze (e.g., `"main.js,utils.js"`)\n - `format`: `"graphtext"` (for human-readable output)\n\n- [ ] **Verify output contains AST nodes**\n - Look for hierarchical structure with indentation\n - Confirm nodes have `semmle.label` with class names\n - Identify relevant AST classes for your query\n\n**Example AST output structure:**\n\n```text\nTopLevelFunction\n\u251C\u2500\u2500 FunctionDeclarationEntry\n\u251C\u2500\u2500 Block\n\u2502 \u251C\u2500\u2500 DeclStmt\n\u2502 \u2502 \u2514\u2500\u2500 LocalVariable\n\u2502 \u251C\u2500\u2500 ExprStmt\n\u2502 \u2502 \u2514\u2500\u2500 FunctionCall\n\u2502 \u2514\u2500\u2500 ReturnStmt\n```\n\n### Step 3: Run PrintCFG Query (if needed)\n\nThe PrintCFG query outputs control flow nodes and edges.\n\n- [ ] **Execute PrintCFG**\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"PrintCFG"`\n - `queryLanguage`: Your language\n - `sourceFunction`: Function name to analyze (e.g., `"processData"`)\n - `format`: `"graphtext"`\n\n- [ ] **Verify output contains nodes and edges**\n - Look for `nodes` section with CFG nodes\n - Look for `edges` section with `\u2192` arrows showing flow\n - Identify control flow patterns (loops, branches)\n\n**Example CFG output structure:**\n\n```text\nnodes\n| node | semmle.label |\n| ... | entry: processData |\n| ... | if (...) |\n| ... | return |\n\nedges\n| from | to | semmle.label |\n| ... | ... | \u2192 |\n```\n\n### Step 4: Run CallGraph Queries (if needed)\n\nCall graph queries help trace function relationships.\n\n- [ ] **Execute CallGraphFrom** (to find what a function calls)\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"CallGraphFrom"`\n - `queryLanguage`: Your language\n - `sourceFunction`: Function name to trace from (e.g., `"main"`)\n - `format`: `"sarif-latest"` or `"csv"`\n\n- [ ] **Execute CallGraphTo** (to find what calls a function)\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"CallGraphTo"`\n - `queryLanguage`: Your language\n - `targetFunction`: Function name to find callers of (e.g., `"validate"`)\n - `format`: `"sarif-latest"` or `"csv"`\n\n- [ ] **Verify call relationships**\n - Confirm results show caller \u2192 callee relationships\n - Note function locations for further analysis\n\n### Step 5: Apply Insights to Query Development\n\nUse the gathered information to inform your query:\n\n- [ ] **From PrintAST**: Identify which AST classes to use in your `from` clause\n- [ ] **From PrintCFG**: Understand execution paths for control-flow-sensitive queries\n- [ ] **From CallGraph**: Map data flow paths through function boundaries\n\n## Common Patterns\n\n### Pattern 1: Finding All Function Calls\n\n```text\n1. Run PrintAST on your source file\n2. Look for FunctionCall, MethodAccess, or similar nodes\n3. Note the parent/child relationships\n4. Use those AST classes in your query\n```\n\n### Pattern 2: Tracing Data Through Functions\n\n```text\n1. Run CallGraphFrom on your entry point function\n2. Identify which functions are called\n3. Run CallGraphTo on sink functions\n4. Map the complete path from source to sink\n```\n\n### Pattern 3: Understanding Loop Structures\n\n```text\n1. Run PrintAST to find loop constructs (ForStmt, WhileStmt, etc.)\n2. Run PrintCFG on the containing function\n3. Identify back edges that represent loop iteration\n4. Use CFG analysis for loop-sensitive queries\n```\n\n## Troubleshooting\n\n| Issue | Likely Cause | Resolution |\n| --------------------- | ------------------------------------- | ------------------------------------------------------ |\n| Empty AST output | `sourceFiles` parameter not matching | Use just filenames, not full paths (e.g., `"test.js"`) |\n| Empty CFG output | `sourceFunction` not found | Check exact function name spelling |\n| Empty CallGraph | No calls exist or wrong function name | Verify function exists and has calls |\n| Query compilation err | Pack dependencies missing | Run #codeql_pack_install on the tools pack |\n\n## MCP Tools Reference\n\n| Tool | Purpose |\n| ------------------------ | ---------------------------------------------------- |\n| #codeql_query_run | Execute tools queries with parameters |\n| #codeql_resolve_database | Validate database before querying |\n| #codeql_database_create | Create database from source code |\n| #codeql_bqrs_interpret | Convert results to different formats |\n| #codeql_pack_install | Install pack dependencies if needed |\n| #codeql_lsp_completion | Explore available types after seeing AST class names |\n| #codeql_lsp_definition | Navigate to class definitions to see predicates |\n| #codeql_lsp_references | Find usage examples of a class or predicate |\n\n### Using LSP Tools After AST Analysis\n\nAfter running PrintAST and identifying relevant AST class names, use the LSP tools\nto explore those classes in your query file:\n\n1. **Write the class name** in your query\'s `from` clause and save the file\n2. **Run #codeql_lsp_completion** after the dot to see member predicates:\n - `file_path`: your query file, `line`/`character`: 0-based position after the dot\n - `workspace_uri`: the pack root directory (containing `codeql-pack.yml`)\n3. **Run #codeql_lsp_definition** on an AST class name to see its full API\n4. **Run #codeql_lsp_references** to find usage examples in the pack\n\n> **Note**: LSP tools use 0-based line/character positions. Run #codeql_pack_install\n> before using them \u2014 they require resolved dependencies. Set `workspace_uri` to\n> a plain directory path (not a `file://` URI).\n\nFor the full iterative LSP development workflow, see: `codeql://prompts/ql_lsp_iterative_development`\n';
|
|
64287
|
+
var tools_query_workflow_prompt_default = '---\nagent: agent\n---\n\n# Using CodeQL Development MCP Server Tools Queries\n\nThis guide helps you use the built-in "tools" queries (`PrintAST`, `PrintCFG`, `CallGraphFrom`, `CallGraphTo`) that ship with the CodeQL Development MCP Server to understand code structure before writing detection queries.\n\n## Why Use Tools Queries?\n\nTools queries provide essential insights into how CodeQL represents your source code:\n\n| Query | Purpose | Use When |\n| --------------- | ------------------------------------------------ | ----------------------------------------------- |\n| `PrintAST` | Visualize the Abstract Syntax Tree | Understanding code structure, finding AST nodes |\n| `PrintCFG` | Visualize Control Flow Graphs | Understanding execution paths, loop/branch flow |\n| `CallGraphFrom` | Find all functions called by a specific function | Tracing data flow through call chains |\n| `CallGraphTo` | Find all functions that call a specific function | Understanding function usage patterns |\n\n## Supported Languages\n\nTools queries are available for: `actions`, `cpp`, `csharp`, `go`, `java`, `javascript`, `python`, `ruby`, `swift`\n\n## Prerequisites\n\nBefore using tools queries, you need:\n\n1. **A CodeQL database** - Either create one or use an existing database\n2. **Source files to analyze** - The tools queries filter output to specific files\n\n## Workflow Checklist\n\n### Step 1: Identify or Create Database\n\n- [ ] **Option A: Use existing database**\n - Tool: #codeql_resolve_database\n - Verify database is valid and note the language\n\n- [ ] **Option B: Create new database**\n - Tool: #codeql_database_create\n - Parameters: `database`, `language`, `source-root`\n\n### Step 2: Run PrintAST Query\n\nThe PrintAST query outputs a hierarchical tree of AST nodes with labels.\n\n- [ ] **Execute PrintAST**\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"PrintAST"`\n - `queryLanguage`: Your language (e.g., `"javascript"`, `"python"`, `"cpp"`)\n - `sourceFiles`: Comma-separated file names to analyze (e.g., `"main.js,utils.js"`)\n - `format`: `"graphtext"` (for human-readable output)\n\n- [ ] **Verify output contains AST nodes**\n - Look for hierarchical structure with indentation\n - Confirm nodes have `semmle.label` with class names\n - Identify relevant AST classes for your query\n\n**Example AST output structure:**\n\n```text\nTopLevelFunction\n\u251C\u2500\u2500 FunctionDeclarationEntry\n\u251C\u2500\u2500 Block\n\u2502 \u251C\u2500\u2500 DeclStmt\n\u2502 \u2502 \u2514\u2500\u2500 LocalVariable\n\u2502 \u251C\u2500\u2500 ExprStmt\n\u2502 \u2502 \u2514\u2500\u2500 FunctionCall\n\u2502 \u2514\u2500\u2500 ReturnStmt\n```\n\n### Step 3: Run PrintCFG Query (if needed)\n\nThe PrintCFG query outputs control flow nodes and edges.\n\n- [ ] **Execute PrintCFG**\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"PrintCFG"`\n - `queryLanguage`: Your language\n - `sourceFunction`: Function name to analyze (e.g., `"processData"`)\n - `format`: `"graphtext"`\n\n- [ ] **Verify output contains nodes and edges**\n - Look for `nodes` section with CFG nodes\n - Look for `edges` section with `\u2192` arrows showing flow\n - Identify control flow patterns (loops, branches)\n\n**Example CFG output structure:**\n\n```text\nnodes\n| node | semmle.label |\n| ... | entry: processData |\n| ... | if (...) |\n| ... | return |\n\nedges\n| from | to | semmle.label |\n| ... | ... | \u2192 |\n```\n\n### Step 4: Run CallGraph Queries (if needed)\n\nCall graph queries help trace function relationships.\n\n- [ ] **Execute CallGraphFrom** (to find what a function calls)\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"CallGraphFrom"`\n - `queryLanguage`: Your language\n - `sourceFunction`: Function name to trace from (e.g., `"main"`)\n - `format`: `"sarif-latest"` or `"csv"`\n\n- [ ] **Execute CallGraphTo** (to find what calls a function)\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"CallGraphTo"`\n - `queryLanguage`: Your language\n - `targetFunction`: Function name to find callers of (e.g., `"validate"`)\n - `format`: `"sarif-latest"` or `"csv"`\n\n- [ ] **Verify call relationships**\n - Confirm results show caller \u2192 callee relationships\n - Note function locations for further analysis\n\n### Step 5: Apply Insights to Query Development\n\nUse the gathered information to inform your query:\n\n- [ ] **From PrintAST**: Identify which AST classes to use in your `from` clause\n- [ ] **From PrintCFG**: Understand execution paths for control-flow-sensitive queries\n- [ ] **From CallGraph**: Map data flow paths through function boundaries\n\n## Common Patterns\n\n### Pattern 1: Finding All Function Calls\n\n```text\n1. Run PrintAST on your source file\n2. Look for FunctionCall, MethodAccess, or similar nodes\n3. Note the parent/child relationships\n4. Use those AST classes in your query\n```\n\n### Pattern 2: Tracing Data Through Functions\n\n```text\n1. Run CallGraphFrom on your entry point function\n2. Identify which functions are called\n3. Run CallGraphTo on sink functions\n4. Map the complete path from source to sink\n```\n\n### Pattern 3: Understanding Loop Structures\n\n```text\n1. Run PrintAST to find loop constructs (ForStmt, WhileStmt, etc.)\n2. Run PrintCFG on the containing function\n3. Identify back edges that represent loop iteration\n4. Use CFG analysis for loop-sensitive queries\n```\n\n## Troubleshooting\n\n| Issue | Likely Cause | Resolution |\n| --------------------- | ------------------------------------- | ------------------------------------------------------ |\n| Empty AST output | `sourceFiles` parameter not matching | Use just filenames, not full paths (e.g., `"test.js"`) |\n| Empty CFG output | `sourceFunction` not found | Check exact function name spelling |\n| Empty CallGraph | No calls exist or wrong function name | Verify function exists and has calls |\n| Query compilation err | Pack dependencies missing | Run #codeql_pack_install on the tools pack |\n\n## MCP Tools Reference\n\n| Tool | Purpose |\n| ------------------------ | ---------------------------------------------------- |\n| #codeql_query_run | Execute tools queries with parameters |\n| #codeql_resolve_database | Validate database before querying |\n| #codeql_database_create | Create database from source code |\n| #codeql_bqrs_interpret | Convert results to different formats |\n| #codeql_pack_install | Install pack dependencies if needed |\n| #codeql_lsp_completion | Explore available types after seeing AST class names |\n| #codeql_lsp_definition | Navigate to class definitions to see predicates |\n| #codeql_lsp_references | Find usage examples of a class or predicate |\n| #search_ql_code | Search QL source files for patterns (text or regex) |\n| #codeql_resolve_files | Find QL files by name, extension, or glob pattern |\n\n### Using LSP Tools After AST Analysis\n\nAfter running PrintAST and identifying relevant AST class names, use the LSP tools\nto explore those classes in your query file:\n\n1. **Write the class name** in your query\'s `from` clause and save the file\n2. **Run #codeql_lsp_completion** after the dot to see member predicates:\n - `file_path`: your query file, `line`/`character`: 0-based position after the dot\n - `workspace_uri`: the pack root directory (containing `codeql-pack.yml`)\n3. **Run #codeql_lsp_definition** on an AST class name to see its full API\n4. **Run #codeql_lsp_references** to find usage examples in the pack\n\n> **Note**: LSP tools use 0-based line/character positions. Run #codeql_pack_install\n> before using them \u2014 they require resolved dependencies. Set `workspace_uri` to\n> a plain directory path (not a `file://` URI).\n\nFor the full iterative LSP development workflow, see: `codeql://prompts/ql_lsp_iterative_development`\n';
|
|
63870
64288
|
|
|
63871
64289
|
// src/prompts/workshop-creation-workflow.prompt.md
|
|
63872
64290
|
var workshop_creation_workflow_prompt_default = '---\nagent: agent\n---\n\n# Creating CodeQL Query Development Workshops\n\nThis guide helps you create educational CodeQL query development workshops from existing production-grade queries. Workshops teach developers how to build queries incrementally through exercises and solutions.\n\n## Workshop Purpose\n\nA CodeQL workshop transforms a complex, production-ready query into a series of incremental learning stages:\n\n- **Exercises**: Incomplete query stubs with scaffolding and hints\n- **Solutions**: Complete working queries for each stage\n- **Tests**: Unit tests validating each stage works correctly\n- **Documentation**: README with learning objectives and instructions\n\n## Prerequisites\n\nBefore creating a workshop, ensure you have:\n\n1. **A production-grade CodeQL query** - The "target" query to decompose\n2. **Working unit tests** - Tests that pass for the target query\n3. **A CodeQL database** - For running tools queries and validating results\n\n## Workshop Creation Checklist\n\n### Phase 1: Analyze the Target Query\n\n- [ ] **Locate query files**\n - Tool: #find_codeql_query_files\n - Parameters: `queryPath` (path to the `.ql` or `.qlref` file)\n - Note: Returns query file, test files, expected results, and metadata\n\n- [ ] **Understand query logic for workshop content**\n - Prompt: `explain_codeql_query`\n - Parameters: `queryPath`, `language`, and optionally `databasePath`\n - Identify: sources, sinks, sanitizers, flow configuration\n - Generates: detailed explanation with mermaid evaluation diagram\n\n- [ ] **Verify existing tests pass**\n - Tool: #codeql_test_run\n - Parameters: `tests` (array of test directories)\n - Confirm: 100% pass rate before proceeding\n\n### Phase 2: Generate AST/CFG Understanding\n\n> **\u26A0\uFE0F CRITICAL**: Run tools queries to understand the test code structure.\n\n- [ ] **Run PrintAST on test code**\n - Tool: #codeql_query_run\n - Parameters:\n - `queryName`: `"PrintAST"`\n - `queryLanguage`: Your language (e.g., `"cpp"`, `"javascript"`)\n - `database`: Path to test database or extracted `.testproj`\n - `sourceFiles`: Test source file names\n - `format`: `"graphtext"`\n - Verify: Output contains hierarchical AST nodes (not empty)\n\n- [ ] **Run PrintCFG on key functions**\n - Tool: #codeql_query_run\n - Parameters:\n - `queryName`: `"PrintCFG"`\n - `queryLanguage`: Your language\n - `database`: Path to database\n - `sourceFunction`: Key function names from test code\n - `format`: `"graphtext"`\n - Verify: Output contains nodes and edges\n\n- [ ] **Run CallGraph queries** (if query involves data flow)\n - Tool: #codeql_query_run\n - Parameters:\n - `queryName`: `"CallGraphFrom"` or `"CallGraphTo"`\n - `database`: Path to database\n - `sourceFunction` / `targetFunction`: Relevant function names\n - Verify: Output shows call relationships\n\n### Phase 3: Plan Workshop Stages\n\nDecompose the query into 4-8 incremental stages using these strategies:\n\n#### Decomposition Strategies\n\n| Strategy | Description | Example Progression |\n| -------------------- | -------------------------------------------------------- | ------------------------------------- |\n| Syntactic \u2192 Semantic | Start with syntax, add type checking, then data flow | AST \u2192 Types \u2192 Local flow \u2192 Global |\n| Local \u2192 Global | Start with local analysis, expand to cross-procedural | Single function \u2192 Multiple functions |\n| Simple \u2192 Filtered | High recall first, then add precision filters | All calls \u2192 Specific calls \u2192 Filtered |\n| Building Blocks | Define helpers, combine into sources/sinks, connect flow | Predicates \u2192 Sources \u2192 Sinks \u2192 Config |\n\n- [ ] **Document stage progression**\n - Stage 1: Basic syntactic pattern (highest recall)\n - Stage 2-N: Add refinements (types, filters, flow)\n - Final Stage: Complete production query\n\n### Phase 4: Create Workshop Structure\n\nStandard workshop directory layout:\n\n```text\nworkshop-name/\n\u251C\u2500\u2500 codeql-workspace.yml # CodeQL workspace configuration\n\u251C\u2500\u2500 README.md # Workshop guide with instructions\n\u251C\u2500\u2500 build-databases.sh # Script to create test databases\n\u251C\u2500\u2500 exercises/ # Student exercise queries\n\u2502 \u251C\u2500\u2500 codeql-pack.yml\n\u2502 \u251C\u2500\u2500 Exercise1.ql\n\u2502 \u251C\u2500\u2500 Exercise2.ql\n\u2502 \u2514\u2500\u2500 ...\n\u251C\u2500\u2500 exercises-tests/ # Tests for exercises\n\u2502 \u251C\u2500\u2500 codeql-pack.yml\n\u2502 \u251C\u2500\u2500 Exercise1/\n\u2502 \u2502 \u251C\u2500\u2500 Exercise1.qlref\n\u2502 \u2502 \u251C\u2500\u2500 Exercise1.expected\n\u2502 \u2502 \u2514\u2500\u2500 test.ext\n\u2502 \u2514\u2500\u2500 ...\n\u251C\u2500\u2500 solutions/ # Complete solution queries\n\u2502 \u251C\u2500\u2500 codeql-pack.yml\n\u2502 \u251C\u2500\u2500 Exercise1.ql\n\u2502 \u251C\u2500\u2500 Exercise2.ql\n\u2502 \u2514\u2500\u2500 ...\n\u251C\u2500\u2500 solutions-tests/ # Tests for solutions\n\u2502 \u251C\u2500\u2500 codeql-pack.yml\n\u2502 \u2514\u2500\u2500 ...\n\u251C\u2500\u2500 tests-common/ # Shared test code\n\u2502 \u2514\u2500\u2500 test.ext\n\u2514\u2500\u2500 graphs/ # AST/CFG visualizations\n \u2514\u2500\u2500 ast-overview.txt\n```\n\n- [ ] **Create codeql-workspace.yml**\n\n ```yaml\n provide:\n - \'*/codeql-pack.yml\'\n ```\n\n- [ ] **Create pack files for each directory**\n - `exercises/codeql-pack.yml`: Query pack depending on language library\n - `exercises-tests/codeql-pack.yml`: Test pack depending on exercises\n - `solutions/codeql-pack.yml`: Query pack (same deps as exercises)\n - `solutions-tests/codeql-pack.yml`: Test pack depending on solutions\n\n### Phase 5: Create Solution Queries\n\nFor each stage, create a complete solution query. Use the iterative LSP tools\nfor efficient development (see `codeql://prompts/ql_lsp_iterative_development`):\n\n- Use #codeql_lsp_completion to explore types and member predicates while writing queries\n- Use #codeql_lsp_definition to navigate to library class definitions\n- Use #find_predicate_position + #quick_evaluate to test predicates in isolation\n- Set `workspace_uri` to the solutions pack root for dependency resolution\n\n- [ ] **Stage 1 Solution**: Simplest working version\n - Basic import statements\n - Minimal from/where/select clause\n - Should produce results (high recall, lower precision)\n\n- [ ] **Intermediate Stages**: Progressive refinements\n - Add type constraints\n - Add helper predicates\n - Filter out false positives\n - Add data flow (if applicable)\n\n- [ ] **Final Stage Solution**: Production-quality query\n - Complete metadata (@name, @description, @kind, @id)\n - Full data flow configuration (if applicable)\n - Proper sanitizers and barriers\n - Matches the original target query\n\n### Phase 6: Create Exercise Queries\n\nTransform solutions into exercises by removing implementation details:\n\n- [ ] **Add scaffolding structure**\n\n ```ql\n /**\n * @name Exercise N - [Topic]\n * @description TODO: Complete this exercise\n * @kind problem\n * @id workshop/exercise-n\n */\n\n import language\n\n // TODO: Define predicate to find [something]\n predicate findSomething(Type t) {\n // Your implementation here\n none()\n }\n\n from Type t\n where findSomething(t)\n select t, "Found something"\n ```\n\n- [ ] **Include helpful comments**\n - Hints about which AST classes to use\n - References to documentation\n - Expected behavior description\n\n- [ ] **Ensure exercises compile**\n - Tool: #codeql_query_compile\n - Exercises should compile (even if tests fail)\n\n### Phase 7: Create Tests\n\n- [ ] **Copy test code to test directories**\n - Use same test code for exercises and solutions\n - Consider `initialize-qltests.sh` script for shared test code\n\n- [ ] **Create .qlref files**\n - Point to query location: `../exercises/ExerciseN.ql`\n\n- [ ] **Create .expected files**\n - Run solution queries to generate expected output\n - Tool: #codeql_test_run with `--learn` flag\n - Or: #codeql_test_accept after running tests\n\n### Phase 8: Validate Workshop\n\n- [ ] **Run all solution tests**\n - Tool: #codeql_test_run\n - Parameters: `tests` pointing to `solutions-tests/`\n - Verify: 100% pass rate\n\n- [ ] **Verify exercise stubs compile**\n - Tool: #codeql_query_compile\n - Parameters: Each exercise query\n - Verify: No compilation errors\n\n- [ ] **Test pack dependencies**\n - Tool: #codeql_pack_install\n - Run in each pack directory\n - Verify: Dependencies resolve correctly\n\n### Phase 9: Create Documentation\n\n- [ ] **Write README.md**\n - Workshop overview and objectives\n - Setup instructions\n - Stage-by-stage learning guide\n - AST/CFG examples from Phase 2\n\n- [ ] **Include AST/CFG visualizations**\n - Save PrintAST output to `graphs/`\n - Reference in README for learning context\n\n## External Workshop Considerations\n\nWhen creating workshops outside the MCP server repository:\n\n- [ ] **Install pack dependencies first**\n\n ```bash\n codeql pack install solutions\n codeql pack install solutions-tests\n ```\n\n- [ ] **Check for initialization scripts**\n - Some workshops use `initialize-qltests.sh` to copy test files\n - Run before executing tests\n\n- [ ] **Use absolute paths with MCP tools**\n - External paths must be absolute\n\n## MCP Tools and Prompts Reference\n\n| Tool/Prompt | Type | Purpose |\n| ------------------------------- | ------ | ---------------------------------------------------------------------- |\n| #find_codeql_query_files | Tool | Locate query and related files |\n| `explain_codeql_query` | Prompt | Generate detailed explanations for workshop learning content |\n| `document_codeql_query` | Prompt | Create/update query documentation files |\n| `ql_lsp_iterative_development` | Prompt | Iterative query development with LSP tools |\n| #codeql_query_run | Tool | Run tools queries (PrintAST, PrintCFG, etc.) |\n| #codeql_test_run | Tool | Validate tests pass |\n| #codeql_test_accept | Tool | Accept test results as expected baseline |\n| #codeql_query_compile | Tool | Verify queries compile |\n| #codeql_pack_install | Tool | Install pack dependencies |\n| #codeql_resolve_metadata | Tool | Extract query metadata |\n| #codeql_lsp_completion | Tool | Explore types and member predicates during query writing |\n| #codeql_lsp_definition | Tool | Navigate to class/predicate definitions in library code |\n| #find_predicate_position | Tool | Locate predicate positions for quick_evaluate |\n| #quick_evaluate | Tool | Test individual predicates against a database |\n| #profile_codeql_query_from_logs | Tool | Parse evaluator logs from a prior query run into a performance profile |\n| #create_codeql_query | Tool | Scaffold new query structure |\n\n## Troubleshooting\n\n| Issue | Likely Cause | Resolution |\n| ------------------------ | ------------------------------- | --------------------------------------------------- |\n| "Nothing to extract" | Missing test source files | Run `initialize-qltests.sh` or copy from shared dir |\n| Pack not found | Older pack version not cached | Run `codeql pack install` in pack directory |\n| Empty AST/CFG output | Wrong sourceFiles/Function | Use just filenames, verify function name spelling |\n| Tests fail unexpectedly | Expected file outdated | Re-run solution and accept with #codeql_test_accept |\n| Exercise doesn\'t compile | Missing imports or syntax error | Ensure valid QL syntax with `none()` placeholder |\n';
|
|
@@ -64049,7 +64467,7 @@ ${content}`
|
|
|
64049
64467
|
workshopCreationWorkflowSchema.shape,
|
|
64050
64468
|
async ({ queryPath, language, workshopName, numStages }) => {
|
|
64051
64469
|
const template = loadPromptTemplate("workshop-creation-workflow.prompt.md");
|
|
64052
|
-
const derivedName = workshopName ||
|
|
64470
|
+
const derivedName = workshopName || basename7(queryPath).replace(/\.(ql|qlref)$/, "").toLowerCase().replace(/[^a-z0-9]+/g, "-") || "codeql-workshop";
|
|
64053
64471
|
const contextSection = buildWorkshopContext(
|
|
64054
64472
|
queryPath,
|
|
64055
64473
|
language,
|
|
@@ -64409,7 +64827,7 @@ var Low = class {
|
|
|
64409
64827
|
};
|
|
64410
64828
|
|
|
64411
64829
|
// ../node_modules/lowdb/lib/adapters/node/TextFile.js
|
|
64412
|
-
import { readFileSync as
|
|
64830
|
+
import { readFileSync as readFileSync10, renameSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
64413
64831
|
import path3 from "node:path";
|
|
64414
64832
|
var TextFileSync = class {
|
|
64415
64833
|
#tempFilename;
|
|
@@ -64422,7 +64840,7 @@ var TextFileSync = class {
|
|
|
64422
64840
|
read() {
|
|
64423
64841
|
let data;
|
|
64424
64842
|
try {
|
|
64425
|
-
data =
|
|
64843
|
+
data = readFileSync10(this.#filename, "utf-8");
|
|
64426
64844
|
} catch (e) {
|
|
64427
64845
|
if (e.code === "ENOENT") {
|
|
64428
64846
|
return null;
|
|
@@ -64473,7 +64891,7 @@ var JSONFileSync = class extends DataFileSync {
|
|
|
64473
64891
|
// src/lib/session-data-manager.ts
|
|
64474
64892
|
init_temp_dir();
|
|
64475
64893
|
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
64476
|
-
import { join as
|
|
64894
|
+
import { join as join18 } from "path";
|
|
64477
64895
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
64478
64896
|
|
|
64479
64897
|
// src/types/monitoring.ts
|
|
@@ -64617,7 +65035,7 @@ var SessionDataManager = class {
|
|
|
64617
65035
|
});
|
|
64618
65036
|
this.storageDir = this.config.storageLocation;
|
|
64619
65037
|
this.ensureStorageDirectory();
|
|
64620
|
-
const adapter = new JSONFileSync(
|
|
65038
|
+
const adapter = new JSONFileSync(join18(this.storageDir, "sessions.json"));
|
|
64621
65039
|
this.db = new Low(adapter, {
|
|
64622
65040
|
sessions: []
|
|
64623
65041
|
});
|
|
@@ -64649,9 +65067,9 @@ var SessionDataManager = class {
|
|
|
64649
65067
|
mkdirSync9(this.storageDir, { recursive: true });
|
|
64650
65068
|
const subdirs = ["sessions-archive", "exports"];
|
|
64651
65069
|
for (const subdir of subdirs) {
|
|
64652
|
-
mkdirSync9(
|
|
65070
|
+
mkdirSync9(join18(this.storageDir, subdir), { recursive: true });
|
|
64653
65071
|
}
|
|
64654
|
-
const configPath =
|
|
65072
|
+
const configPath = join18(this.storageDir, "config.json");
|
|
64655
65073
|
try {
|
|
64656
65074
|
writeFileSync7(configPath, JSON.stringify(this.config, null, 2), { flag: "wx" });
|
|
64657
65075
|
} catch (e) {
|
|
@@ -64830,9 +65248,9 @@ var SessionDataManager = class {
|
|
|
64830
65248
|
if (!session) return;
|
|
64831
65249
|
const date3 = new Date(session.endTime || session.startTime);
|
|
64832
65250
|
const monthDir = `${date3.getFullYear()}-${String(date3.getMonth() + 1).padStart(2, "0")}`;
|
|
64833
|
-
const archiveDir =
|
|
65251
|
+
const archiveDir = join18(this.storageDir, "sessions-archive", monthDir);
|
|
64834
65252
|
mkdirSync9(archiveDir, { recursive: true });
|
|
64835
|
-
const archiveFile =
|
|
65253
|
+
const archiveFile = join18(archiveDir, `${sessionId}.json`);
|
|
64836
65254
|
writeFileSync7(archiveFile, JSON.stringify(session, null, 2));
|
|
64837
65255
|
await this.db.read();
|
|
64838
65256
|
this.db.data.sessions = this.db.data.sessions.filter((s) => s.sessionId !== sessionId);
|
|
@@ -64884,7 +65302,7 @@ var SessionDataManager = class {
|
|
|
64884
65302
|
...this.config,
|
|
64885
65303
|
...configUpdate
|
|
64886
65304
|
});
|
|
64887
|
-
const configPath =
|
|
65305
|
+
const configPath = join18(this.storageDir, "config.json");
|
|
64888
65306
|
writeFileSync7(configPath, JSON.stringify(this.config, null, 2));
|
|
64889
65307
|
logger.info("Updated monitoring configuration");
|
|
64890
65308
|
}
|
|
@@ -64894,7 +65312,7 @@ function parseBoolEnv(envVar, defaultValue) {
|
|
|
64894
65312
|
return envVar.toLowerCase() === "true" || envVar === "1";
|
|
64895
65313
|
}
|
|
64896
65314
|
var sessionDataManager = new SessionDataManager({
|
|
64897
|
-
storageLocation: process.env.MONITORING_STORAGE_LOCATION ||
|
|
65315
|
+
storageLocation: process.env.MONITORING_STORAGE_LOCATION || join18(getProjectTmpBase(), ".ql-mcp-tracking"),
|
|
64898
65316
|
enableMonitoringTools: parseBoolEnv(process.env.ENABLE_MONITORING_TOOLS, false)
|
|
64899
65317
|
});
|
|
64900
65318
|
|
|
@@ -65768,9 +66186,9 @@ init_cli_executor();
|
|
|
65768
66186
|
init_server_manager();
|
|
65769
66187
|
init_package_paths();
|
|
65770
66188
|
init_logger();
|
|
65771
|
-
import_dotenv.default.config({ path:
|
|
66189
|
+
import_dotenv.default.config({ path: resolve13(packageRootDir, ".env"), quiet: true });
|
|
65772
66190
|
var PACKAGE_NAME = "codeql-development-mcp-server";
|
|
65773
|
-
var VERSION = "2.24.3-
|
|
66191
|
+
var VERSION = "2.24.3-rc2";
|
|
65774
66192
|
async function startServer(mode = "stdio") {
|
|
65775
66193
|
logger.info(`Starting CodeQL Development MCP McpServer v${VERSION} in ${mode} mode`);
|
|
65776
66194
|
const codeqlBinary = resolveCodeQLBinary();
|
|
@@ -65824,10 +66242,10 @@ async function startServer(mode = "stdio") {
|
|
|
65824
66242
|
});
|
|
65825
66243
|
const host = process.env.HTTP_HOST || "localhost";
|
|
65826
66244
|
const port = Number(process.env.HTTP_PORT || process.env.PORT) || 3e3;
|
|
65827
|
-
return new Promise((
|
|
66245
|
+
return new Promise((resolve14, reject) => {
|
|
65828
66246
|
const httpServer = app.listen(port, host, () => {
|
|
65829
66247
|
logger.info(`HTTP server listening on http://${host}:${port}/mcp`);
|
|
65830
|
-
|
|
66248
|
+
resolve14();
|
|
65831
66249
|
});
|
|
65832
66250
|
httpServer.on("error", (error2) => {
|
|
65833
66251
|
logger.error("HTTP server error:", error2);
|
|
@@ -65864,7 +66282,7 @@ async function main() {
|
|
|
65864
66282
|
process.exit(1);
|
|
65865
66283
|
}
|
|
65866
66284
|
}
|
|
65867
|
-
var scriptPath = process.argv[1] ?
|
|
66285
|
+
var scriptPath = process.argv[1] ? realpathSync2(resolve13(process.argv[1])) : void 0;
|
|
65868
66286
|
if (scriptPath && import.meta.url === pathToFileURL5(scriptPath).href) {
|
|
65869
66287
|
main();
|
|
65870
66288
|
}
|